MySQL DELETE FROM 以子查询为条件
Posted
技术标签:
【中文标题】MySQL DELETE FROM 以子查询为条件【英文标题】:MySQL DELETE FROM with subquery as condition 【发布时间】:2011-05-27 03:45:21 【问题描述】:我正在尝试这样的查询:
DELETE FROM term_hierarchy AS th
WHERE th.parent = 1015 AND th.tid IN (
SELECT DISTINCT(th1.tid)
FROM term_hierarchy AS th1
INNER JOIN term_hierarchy AS th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
WHERE th1.parent = 1015
);
您可能会说,如果同一个 tid 有其他父级,我想删除与 1015 的父级关系。但是,这会给我一个语法错误:
You have an error in your SQL syntax; check the manual that corresponds to your mysql server version for the right syntax to use near 'AS th
WHERE th.parent = 1015 AND th.tid IN (
SELECT DISTINCT(th1.tid)
FROM ter' at line 1
我检查了文档,并自行运行子查询,这一切似乎都检查了。谁能弄清楚这里出了什么问题?
更新:如下所述,MySQL 不允许您要从中删除的表在条件的子查询中使用。
【问题讨论】:
注意:好答案在底部***.com/a/4471359/956397 只需在DELETE t FROM table t ...
之后添加表格别名
【参考方案1】:
对于在使用子查询时发现此问题希望删除的其他人,我将这个示例留给您以智取 MySQL(即使有些人似乎认为无法做到):
DELETE e.*
FROM tableE e
WHERE id IN (SELECT id
FROM tableE
WHERE arg = 1 AND foo = 'bar');
会给你一个错误:
ERROR 1093 (HY000): You can't specify target table 'e' for update in FROM clause
但是这个查询:
DELETE e.*
FROM tableE e
WHERE id IN (SELECT id
FROM (SELECT id
FROM tableE
WHERE arg = 1 AND foo = 'bar') x);
可以正常工作:
Query OK, 1 row affected (3.91 sec)
将您的子查询包装在一个额外的子查询中(这里命名为 x),MySQL 会很乐意按照您的要求进行操作。
【讨论】:
花了一些时间,但我得到了它的工作。重要提示:1)第一个表必须使用“e”作为别名,2)末尾的“x”不是占位符,它是子查询生成的临时表的别名“(SELECT id FROM tableE WHERE arg = 1 AND foo = 'bar')"。 为什么会这样?这对我来说改变了很多,但此外,它不应该工作。它确实有效,但它不应该。 难以置信。这确实有效!但您不必强制使用 e 为表命名...您可以使用任何您想要的别名。 @jakabadambalazs 我想出它的原因是,以“SELECT id”开头的子查询完成并返回一个 id 列表,因此释放了您要从中删除的表的锁。 @jakabadambalazs:我们不能在 DELETE 及其子 SELECT 中使用同一个表 (e
)。我们可以,但是使用 sub-sub-SELECT 来创建临时表 (x
),并使用 that 作为 sub-SELECT。【参考方案2】:
别名应包含在DELETE
关键字之后:
DELETE th
FROM term_hierarchy AS th
WHERE th.parent = 1015 AND th.tid IN
(
SELECT DISTINCT(th1.tid)
FROM term_hierarchy AS th1
INNER JOIN term_hierarchy AS th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
WHERE th1.parent = 1015
);
【讨论】:
这是一个很好的答案。正确的别名将大大有助于解决类似于原始帖子的问题。 (就像我的一样。)【参考方案3】:您不能指定要删除的目标表。
解决方法
create table term_hierarchy_backup (tid int(10)); <- check data type
insert into term_hierarchy_backup
SELECT DISTINCT(th1.tid)
FROM term_hierarchy AS th1
INNER JOIN term_hierarchy AS th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
WHERE th1.parent = 1015;
DELETE FROM term_hierarchy AS th
WHERE th.parent = 1015 AND th.tid IN (select tid from term_hierarchy_backup);
【讨论】:
我们都是对的 - 请参阅下面他对我的回答的评论。别名语法和逻辑都是问题:) 是的,目前在 MySQL 中似乎无法通过子查询删除 - 感谢您查看它:) 最后一行中的“DELETE FROM term_hierarchy AS th”不是有同样的问题吗?我收到与 OP 相同的语法错误。 您应该将索引添加到 term_hierarchy_backup.tid。 我能够验证,2019 年在 MariaDB 10.3.14 或 MySQL 社区服务器 5.7.27 上都是不可能的【参考方案4】:需要在delete语句中再次引用别名,如:
DELETE th FROM term_hierarchy AS th
....
As outlined here in MySQL docs.
【讨论】:
与别名无关,请再次查看OP @ajreal - 我做到了,请注意错误从别名定义开始,MySQL 文档明确指出您需要在 DELETE 语句和 FROM 子句中使用别名。不过,感谢您的反对。 只需这样做delete from your_table as t1 where t1.id in(select t2.id from your_table t2);
你得到了什么?
文档明确说明; Currently, you cannot delete from a table and select from the same table in a subquery.
dev.mysql.com/doc/refman/5.5/en/delete.html
你不必修复别名,只是不要指定要在删除中选择的目标表......这是真正的问题【参考方案5】:
我以稍微不同的方式处理这个问题,它对我有用;
我需要从我的表中删除 secure_links
,该表引用了 conditions
表,其中不再有任何条件行。基本上是一个家政脚本。这给了我错误 - 您不能指定要删除的目标表。
所以在这里寻找灵感,我想出了下面的查询,它工作得很好。
这是因为它创建了一个临时表 sl1
,用作 DELETE 的引用。
DELETE FROM `secure_links` WHERE `secure_links`.`link_id` IN
(
SELECT
`sl1`.`link_id`
FROM
(
SELECT
`sl2`.`link_id`
FROM
`secure_links` AS `sl2`
LEFT JOIN `conditions` ON `conditions`.`job` = `sl2`.`job`
WHERE
`sl2`.`action` = 'something' AND
`conditions`.`ref` IS NULL
) AS `sl1`
)
为我工作。
【讨论】:
与上面@CodeReaper 中的副本重复...很好的电话... ;)【参考方案6】:delete 中的“in”子句不是...哪里,如果要从子查询返回大量值,效率极低?不知道为什么你不只是内部(或右)加入从ID上的子查询中删除的原始表,而不是我们的“in(子查询)”。?
DELETE T FROM Target AS T
RIGHT JOIN (full subquery already listed for the in() clause in answers above) ` AS TT ON (TT.ID = T.ID)
也许它在“MySQL 不允许它”中得到了回答,但是,它对我来说工作正常,前提是我确保完全阐明要删除的内容(DELETE T FROM Target AS T)。 Delete with Join in MySQL 澄清了 DELETE / JOIN 问题。
【讨论】:
【参考方案7】:如果您想使用 2 个查询来执行此操作,您始终可以执行类似的操作:
1) 从表中获取 id:
SELECT group_concat(id) as csv_result FROM your_table WHERE whatever = 'test' ...
然后用鼠标/键盘或编程语言将结果复制到下面的XXX:
2) DELETE FROM your_table WHERE id IN ( XXX )
也许您可以在一个查询中完成此操作,但这是我更喜欢的。
【讨论】:
【参考方案8】:@CodeReaper,@BennyHill: 它按预期工作。
但是,我想知道表中有数百万行的时间复杂度?显然,在正确索引的表上拥有 5k 条记录需要大约 5ms
来执行。
我的查询:
SET status = '1'
WHERE id IN (
SELECT id
FROM (
SELECT c2.id FROM clusters as c2
WHERE c2.assign_to_user_id IS NOT NULL
AND c2.id NOT IN (
SELECT c1.id FROM clusters AS c1
LEFT JOIN cluster_flags as cf on c1.last_flag_id = cf.id
LEFT JOIN flag_types as ft on ft.id = cf.flag_type_id
WHERE ft.slug = 'closed'
)
) x)```
Or is there something we can improve on my query above?
【讨论】:
【参考方案9】:你可以在删除语句上这样使用别名
DELETE th.*
FROM term_hierarchy th
INNER JOIN term_hierarchy th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
WHERE th.parent = 1015;
【讨论】:
以上是关于MySQL DELETE FROM 以子查询为条件的主要内容,如果未能解决你的问题,请参考以下文章
DELETE FROM 查询上的多个 IN 条件引发 #245 转换类型错误