MySQL将DELETE FROM与子查询作为条件

mik*_*ikl 77 mysql sql subquery in-subquery sql-delete

我正在尝试这样的查询:

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
);
Run Code Online (Sandbox Code Playgroud)

你可以告诉我,如果同一个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
Run Code Online (Sandbox Code Playgroud)

我检查了文档,并自行运行子查询,这一切似乎都检查出来.任何人都可以弄清楚这里有什么问题吗?

更新:如下所述,MySQL不允许您正在删除的表在子查询中用于该条件.

Cod*_*per 256

对于那些在使用子查询时发现这个问题想要删除的人,我给你留下这个例子来说明MySQL(即使有些人似乎认为无法完成):

DELETE e.*
FROM tableE e
WHERE id IN (SELECT id
             FROM tableE
             WHERE arg = 1 AND foo = 'bar');
Run Code Online (Sandbox Code Playgroud)

会给你一个错误:

ERROR 1093 (HY000): You can't specify target table 'e' for update in FROM clause
Run Code Online (Sandbox Code Playgroud)

但是这个查询:

DELETE e.*
FROM tableE e
WHERE id IN (SELECT id
             FROM (SELECT id
                   FROM tableE
                   WHERE arg = 1 AND foo = 'bar') x);
Run Code Online (Sandbox Code Playgroud)

会工作得很好:

Query OK, 1 row affected (3.91 sec)
Run Code Online (Sandbox Code Playgroud)

将子查询包装在另一个子查询中(此处命名为x),MySQL将很乐意按您的要求执行操作.

  • 花了一些时间,但我得到了它的工作.重要:1)第一个表必须别名,如下所示,带"e",2)末尾的"x"不是占位符,它是子查询生成的临时表的别名"(SELECT id FROM tableE WHERE arg = 1 AND foo ='bar')". (10认同)
  • @jakabadambalazs:我们不能在DELETE和子SELECT中使用相同的表(`e`).然而,我们_can_使用子子SELECT创建临时表(`x`),并使用_that_作为子SELECT. (7认同)
  • 为什么这样做?这对我来说有很大的改变,但是,它应该不起作用.它*确实*有效,但它不应该. (3认同)

ajr*_*eal 34

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

解决方法

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);
Run Code Online (Sandbox Code Playgroud)

  • 我可以证实,2019 年在 MariaDB 10.3.14 或 MySQL Community Server 5.7.27 上都不可能 (2认同)

Jam*_*man 33

别名应包含在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
);
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的答案.正确的别名将有助于解决类似于原始帖子的问题.(像我的.) (3认同)

JNK*_*JNK 7

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

DELETE th FROM term_hierarchy AS th
....
Run Code Online (Sandbox Code Playgroud)

正如MySQL文档中所述.

  • 文件明确指出; `目前,您无法从表中删除并从子查询中的同一个表中进行选择.http://dev.mysql.com/doc/refman/5.5/en/delete.html (4认同)
  • 您不必修复别名,只是不要指定用于在删除中选择的目标表......这是真正的问题 (2认同)

小智 6

我以一种略微不同的方式接近它,它对我有用;

我需要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`
            )
Run Code Online (Sandbox Code Playgroud)

适合我.


小智 5

如果子查询返回大量值,delete 中的“in”子句不是非常低效吗?不知道为什么你不只是inner(或right)从子查询上的原始表中加入要删除的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)
Run Code Online (Sandbox Code Playgroud)

也许它在“MySQL 不允许它”中得到了回答,但是,它对我来说工作正常,前提是我确保完全阐明要删除的内容(从目标 AS T 删除 T)。 在 MySQL 中使用 Join 删除澄清了 DELETE / JOIN 问题。