MySQL DELETE FROM以子查询为条件


85

我试图做这样的查询:

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

您可能会说,如果同一提示有其他父母,我想删除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不允许在子查询中使用该条件从中删除要删除的表。


2
注意:底部的好答案stackoverflow.com/a/4471359/956397只需在DELETE t FROM table t ...
PiTheNumber 2014年

Answers:


38

您无法指定要删除的目标表。

解决方法

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

我们都很正确-请在下面查看他对我的回答的评论。别名语法和逻辑都是问题:)
JNK 2010年

是的,似乎目前在MySQL中无法通过子查询删除–感谢您对它的关注:)
mikl 2010年

最后一行中的“从term_hierarchy AS th删除”是否有相同的问题?我收到与OP相同的语法错误。
malhal 2012年

您应该将Index添加到term_hierarchy_backup.tid。
罗曼·纽瓦萨

1
我能够验证,2019年在MariaDB 10.3.14或MySQL Community Server 5.7.27上都不可能实现
alpham8

283

对于其他发现此问题并希望在使用子查询时删除的问题,我将这个示例留给您,以取代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会很乐意完成您的要求。


10
花了一些时间,但我明白了。重要提示:1)必须对第一个表进行别名,如此处所示,以“ e”表示; 2)最后的“ x”不是占位符,它是由子查询“((SELECT id FROM tableE其中arg = 1 AND foo ='bar')“。
Tilman Hausherr

3
为什么这样做?这对我来说变化很大,但是,它不起作用。它确实可以,但是不应该。
donatJ 2014年

1
难以置信的。这实际上有效!但是您不必强制使用e来别名表...您可以使用所需的任何别名。
Andrei Sandulescu 2014年

1
@jakabadambalazs我想出的理由是,以“ SELECT ID”开头的子查询完成并返回ID列表,因此释放了要删除的表的锁。
CodeReaper 2014年

9
@jakabadambalazs:我们不能e在DELETE及其子SELECT中使用相同的表()。但是,我们可以使用sub-sub-SELECT创建一个临时表(x),并将用于sub-SELECT。
史蒂夫·杏仁2014年

38

别名应包含在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
这是一个很好的答案。适当的别名将大大解决与原始帖子类似的问题。(例如Mine。)
usumoio 2013年

9

您需要在delete语句中再次引用别名,例如:

DELETE th FROM term_hierarchy AS th
....

如MySQL文档中此处概述。


与别名无关,请再次检查OP
ajreal 2010年

@ajreal-我做到了,请注意错误始于别名定义,MySQL文档明确指出您需要在DELETE语句和FROM子句中使用别名。不过,谢谢你的反对。
JNK 2010年

只是这样delete from your_table as t1 where t1.id in(select t2.id from your_table t2);做你得到了什么?
ajreal 2010年

4
该文件明确指出;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
比约恩(Björn)2010年

1
您不必修复别名,只需不用指定要删除的目标表即可...这是真正的问题
ajreal 2010年

7

我以略有不同的方式来处理这个问题,对我有用。

我需要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`
            )

为我工作。


5

删除...中的“ 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不允许它”中得到回答,但是,它对我来说很好用,前提是我确保完全阐明要删除的内容(从Target AS T删除T)。 在MySQL中使用Join进行删除可解决DELETE / JOIN问题。


2

如果要使用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 )

也许您可以在一个查询中执行此操作,但这是我的首选。


0

@ CodeReaper,@ BennyHill:它按预期工作。

但是,我想知道表中具有数百万行的时间复杂度吗?显然,由于5ms在正确索引的表上具有5k条记录而要执行。

我的查询:

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?

0

您可以在delete语句中以这种方式使用别名

DELETE  th.*
FROM term_hierarchy th
INNER JOIN term_hierarchy th2 ON (th1.tid = th2.tid AND th2.parent != 1015)
WHERE th.parent = 1015;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.