首页 > 解决方案 > 在 instr() 和 IN 中使用数组的 SQLIte 语句

问题描述

我在构建 sqlite 语句时遇到问题。我很熟悉,instr()但是IN可以一起使用它们吗?我有一个包含多个子字符串的数组,我想查看一列是否包含其中的任何一个。

这是我尝试完成但没有运气的示例

$array = array('-SVA[rev1]', '-KINGS[rev2]', '-TBS[rev3]');

$query2 = $db->query("SELECT * FROM BOT_Downloads WHERE instr( FileName, IN ('$array') ) AND SeriesTitle = 'The Simple Truth' ");

我知道使用LIKE '% %'代替instr()将是另一种方式,但是当将它与 IN 结合使用时,我也无法理解

标签: phpsqlite

解决方案


你的逻辑需要彻底修改;IN 是一条 SQL 语句,用于确定 IN 语句左侧参数的内容是否等于语句括号中的任何文字逗号分隔值,并且不是 INSTR 函数的有效参数。当您尝试执行该语句时,您应该从 SQLite 收到错误。

您当前的代码应生成如下所示的 SQL 查询:

SELECT *
FROM BOT_Downloads
WHERE instr( FileName, IN ('-SVA[rev1],-KINGS[rev2],-TBS[rev3]') )
    AND SeriesTitle = 'The Simple Truth';

我保证这不是你想要的。您想要构建一个看起来更像这样的语句:

SELECT *
FROM BOT_Downloads
WHERE (
    instr( FileName, '-SVA[rev1]') or
    instr( FileName, '-KINGS[rev2]') or
    instr( FileName, '-TBS[rev3]'))
    AND SeriesTitle = 'The Simple Truth’;

顺便说一句,PHP 数组函数不会用单引号包围数组元素,因此您的代码将构建一个如下所示的语句:

SELECT *
FROM BOT_Downloads
WHERE instr( FileName, IN ('-SVA[rev1],-KINGS[rev2],-TBS[rev3]'))
AND SeriesTitle = 'The Simple Truth’;

您可能正在拍摄看起来更像这样的东西:

SELECT *
FROM BOT_Downloads
WHERE instr( FileName, IN ('-SVA[rev1]','-KINGS[rev2]','-TBS[rev3]'))
AND SeriesTitle = 'The Simple Truth’;

但是,由于 IN 子句不是 Instr 函数的有效参数,因此任何一种方式都是错误的。IN 子句要求每个字符串文字都有分隔符,否则它只是一个相等运算符,用于查找括号中包含的一个字符串。PHP 数组方法默认不包含这些分隔符。

继续:

继续我之前的回答,我使用以下 SQL 创建和填充测试表:

BEGIN TRANSACTION;
CREATE TABLE IF NOT EXISTS `BOT_Downloads` (
    `FileName`      TEXT,
    `SeriesTitle`   TEXT,
    `Note`  TEXT
);
INSERT INTO `BOT_Downloads` (FileName,SeriesTitle,Note) VALUES ('File-SVA[rev1].txt','The Simple Truth','matches filename and series title'),
 ('File-KINGS[rev2].txt','The Simple Truth','matches filename and series title'),
 ('File-TBS[rev3].txt','The Simple Truth','matches filename and series title'),
 ('File-WTH[rev1].txt','The Simple Truth','matches series title, doesn’t match filename'),
 ('File-KINGS[rev1].txt','The Simple Truth','matches series title, doesn’t match filename'),
 ('File-SVA[rev1].txt','War and Peace','matches filename, doesn’t match series title'),
 ('File-KINGS[rev2].txt','War and Peace','matches filename, doesn’t match series title'),
 ('File-TBS[rev3].txt','War and Peace','matches filename, doesn’t match series title'),
 ('File-WTH[rev1].txt','War and Peace','No matches'),
 ('File-KINGS[rev1].txt','War and Peace','No matches');
COMMIT;

然后我运行了以下查询:

SELECT *
FROM BOT_Downloads
WHERE (
    instr( FileName, '-SVA[rev1]') or
    instr( FileName, '-KINGS[rev2]') or
    instr( FileName, '-TBS[rev3]'))
   AND SeriesTitle = 'The Simple Truth’;

并得到您要求的性质的结果:

"File-SVA[rev1].txt" "The Simple Truth" "匹配文件名和系列标题" "File-KINGS[rev2].txt" "The Simple Truth" "匹配文件名和系列标题" "File-TBS[rev3 ].txt" "The Simple Truth" "匹配文件名和系列标题"

如果数组的元素是字符串,您所追求的逻辑,使用 PHP 创建一个数组然后将其扩展为 SQL 语句将不起作用,因为 PHP 不会自动将所需的字符串分隔符添加到数组元素;这就是为什么您必须在 IN 语句的查询中手动包含单个刻度线的原因。这适用于整数,但 IMO 是一种不好的方法。由于您没有在要测试的每个单独的字符串元素周围放置字符串分隔符,因此 SQL 引擎似乎正在寻找文件名包含文字字符串 '-SVA[rev1],-KINGS[rev2] 的所有行,-TBS[rev3]' 这不是你要找的,这就是为什么即使没有语法错误你也没有得到结果的原因。


推荐阅读