sqlite 的模式匹配不起作用的原因可能是什么?
What could be the reason why sqlite's pattern match does not work?
我有一个包含日志数据的数据库文件。数据库包含 table LOG
,table 包含列 MSG
。 table 中有 30 行,其中 MSG
列包含行尾的字符串 "down":
$ sqlite3 log.db "select msg from log" | grep down$ | wc -l
30
但是当我尝试使用 LIKE
查找它们时,我找不到匹配项:
$ sqlite3 log.db "select msg from log where msg like '%down'" | grep down$ | wc -l
0
这可能是什么原因?
更新:MCVE
CREATE TABLE LOG (MSG VARCHAR(6291456) NOT NULL);
INSERT INTO LOG VALUES (X'666163696c6974793d6461656d6f6e3b636f6d706f6e656e743d6e616d65643b746578743d7368757474696e6720646f776e');
SELECT MSG FROM LOG; -- returns the row
SELECT MSG FROM LOG WHERE MSG LIKE '%down'; -- returns nothing
SELECT MSG FROM LOG WHERE MSG LIKE '%down%'; -- returns nothing
SELECT MSG FROM LOG WHERE CAST(MSG AS VARCHAR) LIKE '%down'; -- returns the row
我不知道为什么从 VARCHAR
到 VARCHAR
的转换会有所不同。
更新:另一个 MCVE
CREATE TABLE LOG (MSG VARCHAR(6291456) NOT NULL);
INSERT INTO LOG VALUES (X'666163696c6974793d6461656d6f6e3b636f6d706f6e656e743d6e616d65643b746578743d7368757474696e6720646f776e');
INSERT INTO LOG VALUES ('facility=daemon;component=named;text=shutting down');
SELECT ROWID,MSG FROM LOG; -- returns both rows
SELECT ROWID,MSG FROM LOG WHERE MSG LIKE '%down'; -- returns just the second
SELECT ROWID,MSG FROM LOG WHERE MSG LIKE '%down%'; -- returns just the second
SELECT ROWID,MSG FROM LOG WHERE CAST(MSG AS VARCHAR) LIKE '%down'; -- returns both rows
SELECT HEX(MSG) FROM LOG;
我会把它粘贴到评论中,但格式看起来很难看。它对我有用:
$ sqlite3 log.db
SQLite version 3.24.0 2018-06-04 14:10:15
Enter ".help" for usage hints.
sqlite> create table log (id int, msg text);
sqlite> insert into log values (1,'database is down');
sqlite> insert into log values (2,'database is down');
sqlite> insert into log values (3,'database is down');
sqlite> ^D
$ sqlite3 log.db "select msg from log" | grep down$ | wc -l
3
$ sqlite3 log.db "select msg from log where msg like '%down'" | grep down$ | wc -l
3
能否分享您的 log
table 的内容,以便我尝试重现您的问题?
鉴于您的示例数据和您在不同版本的 sqlite 上看到的结果,我确定这是正在发生的事情。
首先,您要将 blob 插入 table,而不是字符串。这些 blob 存储不变,而不是像您正在使用的那样将数值转换为具有 TEXT
亲和力的列的字符串。有关列关联和隐式数据类型转换的详细信息,请参阅 the documentation。
其次,与这些 blob 不匹配的 sqlite3 实例是在打开 SQLITE_LIKE_DOESNT_MATCH_BLOBS
配置选项的情况下构建的,而与它们匹配的实例是在关闭它(默认设置)的情况下构建的。
This compile-time option causes the LIKE operator to always return False if either operand is a BLOB. The default behavior of LIKE is that BLOB operands are cast to TEXT before the comparison is done.
如果您检查 PRAGMA compile_options
输出,您应该能够验证它正在被使用。
我有一个包含日志数据的数据库文件。数据库包含 table LOG
,table 包含列 MSG
。 table 中有 30 行,其中 MSG
列包含行尾的字符串 "down":
$ sqlite3 log.db "select msg from log" | grep down$ | wc -l
30
但是当我尝试使用 LIKE
查找它们时,我找不到匹配项:
$ sqlite3 log.db "select msg from log where msg like '%down'" | grep down$ | wc -l
0
这可能是什么原因?
更新:MCVE
CREATE TABLE LOG (MSG VARCHAR(6291456) NOT NULL);
INSERT INTO LOG VALUES (X'666163696c6974793d6461656d6f6e3b636f6d706f6e656e743d6e616d65643b746578743d7368757474696e6720646f776e');
SELECT MSG FROM LOG; -- returns the row
SELECT MSG FROM LOG WHERE MSG LIKE '%down'; -- returns nothing
SELECT MSG FROM LOG WHERE MSG LIKE '%down%'; -- returns nothing
SELECT MSG FROM LOG WHERE CAST(MSG AS VARCHAR) LIKE '%down'; -- returns the row
我不知道为什么从 VARCHAR
到 VARCHAR
的转换会有所不同。
更新:另一个 MCVE
CREATE TABLE LOG (MSG VARCHAR(6291456) NOT NULL);
INSERT INTO LOG VALUES (X'666163696c6974793d6461656d6f6e3b636f6d706f6e656e743d6e616d65643b746578743d7368757474696e6720646f776e');
INSERT INTO LOG VALUES ('facility=daemon;component=named;text=shutting down');
SELECT ROWID,MSG FROM LOG; -- returns both rows
SELECT ROWID,MSG FROM LOG WHERE MSG LIKE '%down'; -- returns just the second
SELECT ROWID,MSG FROM LOG WHERE MSG LIKE '%down%'; -- returns just the second
SELECT ROWID,MSG FROM LOG WHERE CAST(MSG AS VARCHAR) LIKE '%down'; -- returns both rows
SELECT HEX(MSG) FROM LOG;
我会把它粘贴到评论中,但格式看起来很难看。它对我有用:
$ sqlite3 log.db
SQLite version 3.24.0 2018-06-04 14:10:15
Enter ".help" for usage hints.
sqlite> create table log (id int, msg text);
sqlite> insert into log values (1,'database is down');
sqlite> insert into log values (2,'database is down');
sqlite> insert into log values (3,'database is down');
sqlite> ^D
$ sqlite3 log.db "select msg from log" | grep down$ | wc -l
3
$ sqlite3 log.db "select msg from log where msg like '%down'" | grep down$ | wc -l
3
能否分享您的 log
table 的内容,以便我尝试重现您的问题?
鉴于您的示例数据和您在不同版本的 sqlite 上看到的结果,我确定这是正在发生的事情。
首先,您要将 blob 插入 table,而不是字符串。这些 blob 存储不变,而不是像您正在使用的那样将数值转换为具有 TEXT
亲和力的列的字符串。有关列关联和隐式数据类型转换的详细信息,请参阅 the documentation。
其次,与这些 blob 不匹配的 sqlite3 实例是在打开 SQLITE_LIKE_DOESNT_MATCH_BLOBS
配置选项的情况下构建的,而与它们匹配的实例是在关闭它(默认设置)的情况下构建的。
This compile-time option causes the LIKE operator to always return False if either operand is a BLOB. The default behavior of LIKE is that BLOB operands are cast to TEXT before the comparison is done.
如果您检查 PRAGMA compile_options
输出,您应该能够验证它正在被使用。