SQL 包含嵌套选择的删除语句

SQL Delete statement with nested selects

我正在尝试在 DELETE 语句中创建子查询以提高性能。普通 DELETE 语句有效,但子查询语句要么不加区别地删除所有行,要么每次调用只删除一行。我对为什么这些陈述不等价感到困惑。

跳转到“什么不起作用”以查看问题陈述。

前期信息

我正在使用 python2 中的 sqlite3 来管理带有相关标签的图片数据库。

table 的架构是:

CREATE VIRTUAL TABLE "files" USING fts3(fname TEXT, orig_name TEXT, tags TEXT, md5sum TEXT);

标签被组织为逗号分隔的列表,因此 sqlite 中的直接字符串比较不(容易)起作用,所以我添加了一个辅助函数 TAGMATCH

def tag_match(tags, m):
    i = int(m in [i.strip() for i in tags.split(',')])
    return i
db.create_function('TAGMATCH', 2, tag_match)

什么有效

这就是我做的 want/expect。它会删除列 tags 包含标记 'DELETE' 的所有行。缺点是,据我所知,这需要对 table 进行线性扫描。由于从 table 中删除某些内容的“危险”,我确实想使用 MATCH 以防万一,在某些假设情况下,与另一个意外标记发生匹配,即。 'DO NOT DELETE THIS'.

DELETE FROM files WHERE TAGMATCH(tags, 'DELETE')


什么不起作用

为了加快速度,我尝试了在另一个 Whosebug post 中阅读的技巧,其中 MATCH 用于缩小搜索范围,然后对这些结果进行直接字符串比较,即

SELECT * FROM (SELECT * FROM table WHERE words MATCH keyword) WHERE words = keyword

我在这里尝试使用这个技巧,但它删除了 table.

中的每一行
DELETE FROM files WHERE TAGMATCH((
        SELECT tags FROM files WHERE tags MATCH 'DELETE'), 'DELETE')

这是我第一次想到的。我现在意识到这不是一个特别好的解决方案,但由于它的效果令我困惑,所以我将其包括在内。此语句仅删除包含标记 'DELETE' 的一行。如果再次调用,它会删除另一行,依此类推,直到删除所有带有 'DELETE' 的行:

DELETE FROM files WHERE rowid = (
        SELECT rowid FROM (
            SELECT rowid, tags FROM files WHERE tags MATCH 'DELETE')
    WHERE TAGMATCH(tags, 'DELETE'))

以下查询将删除所有内容,因为 WHERE 子句计算为一个数字,如果它本身计算为 TRUE:

DELETE FROM files WHERE TAGMATCH((
        SELECT tags FROM files WHERE tags MATCH 'DELETE'), 'DELETE')

相当于

DELETE FROM files WHERE 1  -- or whatever ##

相反,考虑将 EXISTS 与与主查询相关的子查询一起使用:

DELETE FROM files WHERE EXISTS
    (SELECT 1 
     FROM (SELECT rowid, tags FROM files WHERE tags MATCH 'DELETE') sub 
     WHERE TAGMATCH(sub.tags, 'DELETE') AND sub.rowid = files.rowid)

或者,使用您的尝试,将 = 变成 IN,因为前者仅使用找到的第一条记录。

DELETE FROM files WHERE rowid IN
    (SELECT rowid 
     FROM (SELECT rowid, tags FROM files WHERE tags MATCH 'DELETE') sub
     WHERE TAGMATCH(sub.tags, 'DELETE'))