SQLite 'long' 整数由 SQL select 查询返回 truncated/incorrect — 如何检索正确的值? (SQLite ODBC driver, VBA/ADODB)
SQLite 'long' integers are returned truncated/incorrect by SQL select query — how can the correct values be retrieved? (SQLite ODBC driver, VBA/ADODB)
在 Excel VBA 和 SQLite ODBC Driver 中,我针对单个 table 的简单 SELECT 查询 运行 检索 'long' 整数(10 位或更多小数位)不正确。如何在没有 t运行cation 或任何乱码的情况下正确检索这些值?
(请注意: 数据库 structure/field 定义无法修改 — 数据库属于开源应用程序,Anki,更改结构会破坏软件。)
我正在查询的特定 table 包含(至少)几个可以包含更长整数值(10 位或更多小数位)的字段。主键(“id”)包含Unix时间戳(datetime)值,以毫秒为单位,所以主键字段中的整数总是占小数点后13位。
这里是 table 定义:
CREATE TABLE "notes" (
"id" integer,
"guid" text NOT NULL,
"mid" integer NOT NULL,
"mod" integer NOT NULL,
"usn" integer NOT NULL,
"tags" text NOT NULL,
"flds" text NOT NULL,
"sfld" integer NOT NULL,
"csum" integer NOT NULL,
"flags" integer NOT NULL,
"data" text NOT NULL,
PRIMARY KEY("id")
);
我的一条记录在 id 字段中的值为 1640497387755。如果我 运行 这个查询:
SELECT id AS primarykey, flds FROM notes WHERE id = 1640497387755
结果在 primarykey
字段(1 条记录的 ADO 记录集)中包含 2147483647,而不是 1640497387755。但是,记录集中的 flds
字段具有正确的(文本)数据。
我已通过使用单独的工具 (DB Browser for SQLite) 浏览数据库验证该字段包含 correct/expected Unix 时间戳值。进一步注意,我可以根据数据库中的实际 id
字段值使用 WHERE 子句 select 正确的记录,如上面的 SELECT
语句.
将字段转换为 BigInt 和 BigInteger 不会影响结果——例如,我得到完全相同的结果:
SELECT CAST(id as biginteger) AS primarykey, flds FROM notes
都没有为 ADODB 连接设置 BigInt 参数,如下面我的代码所示(参见
documentation for the SQL ODBC Driver,在“DSN-less 连接的连接字符串参数”标题下。
这里是工作 VBA 代码的最小示例,充分展示了该问题的所有令人沮丧的地方:
Sub ADOQueryAnki()
Dim conn As Object, rst As Object
Dim varRecords() As Variant
Dim strDBasePath As String
Dim strSQLSelect As String
Set conn = CreateObject("ADODB.Connection")
Set rst = CreateObject("ADODB.Recordset")
strDBasePath = "I:\Anki\Test\collection.anki2;"
' collection.anki2 is a standard SQLite database
' --though the filename has a non-standard extension
strSQLSelect = "SELECT id as primarykey, flds FROM notes"
' OPEN CONNECTION
conn.Open "DRIVER=SQLite3 ODBC Driver;Database=" & strDBasePath & ";BigInt = true"
conn.CursorLocation = adUseClient
rst.Open strSQLSelect, conn, adOpenDynamic, adLockOptimistic ' have tried multiple options
Debug.Print rst!primarykey
End Sub
我刚才做的运行中,Debug.Print
语句输出2147483647,其中数据库中对应字段的实际值为1324302169120。
请注意,记录集中字段的 ActualSize
和 DefinedSize
属性在 VBA 调试器中均显示为“4”,意思是(我认为)4 个字节,而 SQLite 使用 8 个字节将这些值存储在数据库中。
如评论所述,问题本质上源于 如何 在连接字符串中包含 BigInt
参数。虽然 MSDN documentation 似乎与实现不同,但 key/value 对应避免空格:
DRIVER=SQLite3 ODBC Driver;Database=" & strDBasePath & ";BigInt=true"
调试 ODBC 连接字符串的特殊属性的经验教训:
- 避免前后空格,对特殊字符串属性使用单引号;
- 对于布尔属性,检查是否区分大小写(
true
vs True
),整数(0, 1)同义词,字符串(yes/no)同义词;
- 对于结束属性,检查标点符号,例如结束分号;
- 运行 使用默认参数的原始版本的连接和记录集,没有特殊配置,例如
CursorLocation
、CursorType
和 LockType
;
- 使用支持 ODBC 作为控制检查以隔离环境或接口问题的其他语言(即 Python、PowerShell)进行调试;
- 仔细阅读特定 ODBC 驱动程序或 library/module 和 API(如 ADO)的文档。
在 Excel VBA 和 SQLite ODBC Driver 中,我针对单个 table 的简单 SELECT 查询 运行 检索 'long' 整数(10 位或更多小数位)不正确。如何在没有 t运行cation 或任何乱码的情况下正确检索这些值?
(请注意: 数据库 structure/field 定义无法修改 — 数据库属于开源应用程序,Anki,更改结构会破坏软件。)
我正在查询的特定 table 包含(至少)几个可以包含更长整数值(10 位或更多小数位)的字段。主键(“id”)包含Unix时间戳(datetime)值,以毫秒为单位,所以主键字段中的整数总是占小数点后13位。
这里是 table 定义:
CREATE TABLE "notes" (
"id" integer,
"guid" text NOT NULL,
"mid" integer NOT NULL,
"mod" integer NOT NULL,
"usn" integer NOT NULL,
"tags" text NOT NULL,
"flds" text NOT NULL,
"sfld" integer NOT NULL,
"csum" integer NOT NULL,
"flags" integer NOT NULL,
"data" text NOT NULL,
PRIMARY KEY("id")
);
我的一条记录在 id 字段中的值为 1640497387755。如果我 运行 这个查询:
SELECT id AS primarykey, flds FROM notes WHERE id = 1640497387755
结果在 primarykey
字段(1 条记录的 ADO 记录集)中包含 2147483647,而不是 1640497387755。但是,记录集中的 flds
字段具有正确的(文本)数据。
我已通过使用单独的工具 (DB Browser for SQLite) 浏览数据库验证该字段包含 correct/expected Unix 时间戳值。进一步注意,我可以根据数据库中的实际 id
字段值使用 WHERE 子句 select 正确的记录,如上面的 SELECT
语句.
将字段转换为 BigInt 和 BigInteger 不会影响结果——例如,我得到完全相同的结果:
SELECT CAST(id as biginteger) AS primarykey, flds FROM notes
都没有为 ADODB 连接设置 BigInt 参数,如下面我的代码所示(参见 documentation for the SQL ODBC Driver,在“DSN-less 连接的连接字符串参数”标题下。
这里是工作 VBA 代码的最小示例,充分展示了该问题的所有令人沮丧的地方:
Sub ADOQueryAnki()
Dim conn As Object, rst As Object
Dim varRecords() As Variant
Dim strDBasePath As String
Dim strSQLSelect As String
Set conn = CreateObject("ADODB.Connection")
Set rst = CreateObject("ADODB.Recordset")
strDBasePath = "I:\Anki\Test\collection.anki2;"
' collection.anki2 is a standard SQLite database
' --though the filename has a non-standard extension
strSQLSelect = "SELECT id as primarykey, flds FROM notes"
' OPEN CONNECTION
conn.Open "DRIVER=SQLite3 ODBC Driver;Database=" & strDBasePath & ";BigInt = true"
conn.CursorLocation = adUseClient
rst.Open strSQLSelect, conn, adOpenDynamic, adLockOptimistic ' have tried multiple options
Debug.Print rst!primarykey
End Sub
我刚才做的运行中,Debug.Print
语句输出2147483647,其中数据库中对应字段的实际值为1324302169120。
请注意,记录集中字段的 ActualSize
和 DefinedSize
属性在 VBA 调试器中均显示为“4”,意思是(我认为)4 个字节,而 SQLite 使用 8 个字节将这些值存储在数据库中。
如评论所述,问题本质上源于 如何 在连接字符串中包含 BigInt
参数。虽然 MSDN documentation 似乎与实现不同,但 key/value 对应避免空格:
DRIVER=SQLite3 ODBC Driver;Database=" & strDBasePath & ";BigInt=true"
调试 ODBC 连接字符串的特殊属性的经验教训:
- 避免前后空格,对特殊字符串属性使用单引号;
- 对于布尔属性,检查是否区分大小写(
true
vsTrue
),整数(0, 1)同义词,字符串(yes/no)同义词; - 对于结束属性,检查标点符号,例如结束分号;
- 运行 使用默认参数的原始版本的连接和记录集,没有特殊配置,例如
CursorLocation
、CursorType
和LockType
; - 使用支持 ODBC 作为控制检查以隔离环境或接口问题的其他语言(即 Python、PowerShell)进行调试;
- 仔细阅读特定 ODBC 驱动程序或 library/module 和 API(如 ADO)的文档。