用Perl将简化的SQL查询解析为SQLite
我正在尝试将一个“简化”的sql查询转换为一个可工作的SQLite查询,以用于XnViews数据库,这意味着对于我正在尝试做的事情,数据库布局充其量是次优的,对此我不能做任何更改 例如“(第10类和第12类)和(第5类或第7类)” 这应该针对表“t3”使用,表中有字段“if”(文件ID)和“ic”(类别ID) 条目如下所示:用Perl将简化的SQL查询解析为SQLite,sql,sqlite,parsing,Sql,Sqlite,Parsing,我正在尝试将一个“简化”的sql查询转换为一个可工作的SQLite查询,以用于XnViews数据库,这意味着对于我正在尝试做的事情,数据库布局充其量是次优的,对此我不能做任何更改 例如“(第10类和第12类)和(第5类或第7类)” 这应该针对表“t3”使用,表中有字段“if”(文件ID)和“ic”(类别ID) 条目如下所示: if, ic 7, 10 7, 12 7, 4 9, 10 9, 12 9, 5 10, 10 10, 12 10, 7 上面的简化查询应该只选择文件9和10,因为7有想
if, ic
7, 10
7, 12
7, 4
9, 10
9, 12
9, 5
10, 10
10, 12
10, 7
上面的简化查询应该只选择文件9和10,因为7有想要的类别10和12,但既没有5也没有7
现在的实际问题是构建一个地狱般的查询语句,因为我已经花了几个小时来简单地获得两个类别之间的AND
SELECT if FROM t3 WHERE ic IN (10, 12) GROUP BY if HAVING count(if) = 2
这给了我所有包含类别10和12的文件ID,但我不知道如何将它们与剩余的“and(cat_5或cat_7)”结合起来
当我计划这些简化的sql语句(由html和js中的click it together builder生成)时,我计划简单地将“cat_5”替换为“t3.ic=5”,其余的保持原样
当然,我没有预见到它不会作为一个整体检查条目,不可能有ic=5和ic=7。这几乎破坏了一切
所以我想知道是否有人知道我如何在实际工作中翻译这些简单的查询,记住它可能不限于(x和y)对
编辑:我想出了如何做我给出的例子,我认为至少:
SELECT if FROM t3 WHERE ic IN (10, 12) GROUP BY if HAVING count(if) = 2
INTERSECT
SELECT if FROM t3 WHERE ic IN (5, 7) GROUP BY if
但是现在的主要问题是以正确的顺序解决()问题
编辑2:我想我正在尝试使用group_concat()将类别分组到一个字段中,然后我应该能够简单地将“”这样的小块放在一起,然后只使用括号,它应该可以工作。突出显示“应该”。您的原始查询不符合预期
其中,如果(10,12)组中的ic具有count(if)=2,则即使您再次在10和10中有ic
s,但根本没有12,也会产生正确的结果。这与您对所需内容的文字描述背道而驰。这里需要一个内部查询来获取12和10的结果。你可以在我下面发布的fiddle链接中测试你的查询是否失败
有点棘手,但这是我将如何解释它直截了当
SELECT DISTINCT ifc
FROM t3
WHERE ifc IN (
SELECT ifc
FROM t3
WHERE ic = 10
GROUP BY ifc
HAVING COUNT(*) > 0
INTERSECT
SELECT ifc
FROM t3
WHERE ic = 12
GROUP BY ifc
HAVING COUNT(*) > 0
)
AND ic IN (5, 7)
我没有带来任何优化,你可以试试你的。fiddle链接是Postgres的链接,但这应该可以工作(没有让SQLite在我的浏览器中工作:()
Edit:CL。指出了一件有趣的事情,即不必在内部查询中包含和子句,这是正确的。我用SQL术语解释OP的要求,目的是在不考虑任何优化的情况下把事情弄清楚
下面是一个外观更好的查询:
SELECT DISTINCT ifc
FROM t3
WHERE ifc IN (
SELECT ifc
FROM t3
WHERE ic = 10
INTERSECT
SELECT ifc
FROM t3
WHERE ic = 12
)
AND ic IN (5, 7)
好吧,我让它按照我最初的计划运行
SELECT Folders.Pathname || Images.Filename AS File FROM Images
JOIN Folders ON Images.FolderID = Folders.FolderID
LEFT JOIN (
SELECT f, Cats, t4.if AS Tagged FROM t2
JOIN (
SELECT if, ' ' || group_concat(ic,' ') || ' ' AS Cats FROM t3 GROUP BY if
) st3 ON t2.i = st3.if
LEFT JOIN t4 ON t2.i = t4.if
) st2 ON File = st2.f
$selectWhereImage $sqlqry
ORDER BY ModifiedDate $order LIMIT $offset, $limit
我知道这是一个地狱般的查询,但它将我要查找的所有内容(类别ID、标记与否、分级、颜色)按日期排序,结果是完整的文件路径
这可能是一种可怕的方法,但如果有人找到一种更好的工作方式,我可以简单地替换“cat_5”这样的占位符,同时保持括号和运算符所需的其他占位符不变,那么我将洗耳恭听:D
噢,$selectWhereImage只包含一个较长的文件,限制文件以imageformat结尾,$sqlqry是从上面重新安装的东西,cat_5会变成像“%5%”这样的猫。,因为cat的左右两侧都有额外的空格,我可以匹配任何数字,而不会在“10”中找到“1”,因为“1”在“10”:D中不是一种更简单、更快的黑客方法吗
SELECT DISTINCT ifc
FROM t3
WHERE ifc IN (
SELECT ifc
FROM t3
WHERE ic = 10
)
AND ifc IN (
SELECT ifc
FROM t3
WHERE ic = 12
)
AND ic IN (5, 7)
如果您必须像以前那样使用intersect,那么您应该更改您的上一个查询,这是错误的。因为您必须确保每个如果都有10和12 asic
,那么如果没有两个单独的查询,您就无法逃脱。例如:
SELECT ifc
FROM t3
WHERE ifc IN (
SELECT ifc
FROM t3
WHERE ic = 10
)
AND ifc IN (
SELECT ifc
FROM t3
WHERE ic = 12
)
INTERSECT
SELECT ifc FROM t3 WHERE ic IN (5, 7)
INTERSECT
将在此处处理组,因此您不必显式添加,但这不会像我的其他查询那样有效。如果您必须避开子查询,可以使用JOIN
:
SELECT DISTINCT t.ifc
FROM t3 AS t
JOIN t3 AS v ON v.ifc = t.ifc
JOIN t3 AS p ON p.ifc = t.ifc
WHERE v.ic = 10 AND p.ic = 12 AND t.ic IN (5, 7)
第二种方法的优点是,它可以在不知道交集的数据库上工作,比如MySQL。与我昨晚的计算结果不同:从t3中选择if,其中ic在(10,12)组中,通过if have count(if)=2交集从t3中选择if,其中ic在(5,7)组中
现在,我正试图找出如果能够以正确的顺序解析()的话,哪一个更容易使用。我还想稍微改变一下简单的语法,将()限制为be和or,或者通过执行([和|或]cat|u 1 cat_2 cat_3)但是()停留。@CL.非常好,+1,我错过了。谢谢你的指点,我将编辑我的答案:)正如我所说,我将OP对SQL的要求解释为有意义的,而不是优化查询。@BloodyRain2k你发布的查询是错误的,请在回答中查看我对它的评论。请发布一个回答,解决你发布的问题。SO中没有人对阅读您的代码库感兴趣。