我在 sqlite 中处理十六进制数字时遇到问题。
给定一个包含数字的 CSV 文件,其中一个写为十六进制 (0x1)
❯ cat my.csv
A,B
1,0x1
导入并检查架构
❯ sqlite3 my.db ".import --csv my.csv somet"
❯ sqlite3 my.db ".schema somet"
CREATE TABLE IF NOT EXISTS "somet"(
"A" TEXT, "B" TEXT);
现在我们可以选择 A 作为实数(没有单引号),但 B 不能。
❯ sqlite3 my.db "select * from somet where a = 0x1;"
1|0x1
❯ sqlite3 my.db "select * from somet where b = 0x1;"
这出乎我的意料。我们可以看到,在对 A 列进行过滤时,SQLite 可以理解数字的十六进制表示形式,但不能对 B 列进行过滤。
在查看 A 的输出时,我们还看到 b 并未存储为数字,而是似乎存储为二进制十六进制字符串。
那么,鉴于sqlite3理解十六进制表示,并且它将使用数字作为“数字”,当导入csv时,为什么B不作为数字导入?
sqlite3
shell 进行CSV 导入会将值作为字符串插入。任何到其他存储类型的转换都是由底层
INSERT
基于列类型及其亲和性完成的。
表格的
B
列具有 TEXT
类型,这意味着它具有文本亲和力;所有内容都存储为字符串(空值和 blob 除外)。如果您为列提供具有数字亲和力的类型,例如 INTEGER
,则包含整数文字的字符串将转换为整数,除了
...十六进制整数文字不被认为是格式正确的,并且存储为 TEXT。 (这样做是为了与 3.8.6 2014-08-15 版本之前的 SQLite 版本保持历史兼容性,其中十六进制整数文字首次引入 SQLite。)
在导入之前,您必须更改 ETL 流程,将这些十六进制值替换为以 10 为基数的整数(并提前创建具有正确列类型的表),或者编写更智能的导入脚本。