嵌套选择

时间:2017-11-21 21:02:13

标签: python sql sqlite fts3

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

跳到"什么不起作用"看问题陈述。

前端信息

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

该表的架构是:

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)

什么有效

这就是我想要/期望的。它会删除列tags包含标记'DELETE'的所有行。根据我的理解,下行是需要对表格进行线性扫描。由于"危险"删除表中的某些内容我确实想要使用MATCH以防万一,在某些假设的情况下,匹配会发生另一个非预期的标记,即。 'DO NOT DELETE THIS'

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

什么不起作用

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

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

我尝试在这里使用这个技巧,但它会删除表中的每一行。

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'))

1 个答案:

答案 0 :(得分:2)

以下查询删除所有内容,因为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'))