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'))
我正在尝试在 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'))