如何在MySQL中从选择中删除?


86

此代码不适用于MySQL 5.0,如何重写使其正常工作

DELETE FROM posts where id=(SELECT id FROM posts GROUP BY id  HAVING ( COUNT(id) > 1 ))

我想删除没有唯一ID的列。我会在大多数情况下添加唯一的一个ID(我尝试了in语法,它也不起作用)。

Answers:


212

SELECT(子)查询返回结果。因此,您需要使用IN,而不是=WHERE子句中使用。

此外,如该答案所示,您不能在同一查询中的子查询中修改同一表。但是,您可以SELECT然后DELETE在单独的查询中进行嵌套,也可以嵌套另一个子查询并为内部子查询结果添加别名(尽管看起来有些怪异):

DELETE FROM posts WHERE id IN (
    SELECT * FROM (
        SELECT id FROM posts GROUP BY id HAVING ( COUNT(id) > 1 )
    ) AS p
)

或使用Mchl建议的联接


1
我的桌子上有150个重复的钥匙。我执行了上面的查询,并说“受影响的144行”,但是那里仍然有重复的键。因此,我再次执行了查询,并说受影响的5行再次出现:受影响的1行。然后所有重复的键都消失了。为什么是这样?
亚历克斯(Alex)

之所以发生这种情况,是因为您仅从每组重复项中删除了一项:SELECT id FROM posts GROUP BY id HAVING ( COUNT(id) > 1 )
havvg

#1248-每个派生表都必须具有自己的别名
thang 2015年

@thang:这就是为什么我说要对内部子查询起别名的原因。
BoltClock

1
您能否解释一下“ A p”是什么意思?
板球

22
DELETE 
  p1
  FROM posts AS p1 
CROSS JOIN (
  SELECT ID FROM posts GROUP BY id HAVING COUNT(id) > 1
) AS p2
USING (id)

这似乎可行,但是我对语法感到困惑,无法在其他地方找到任何资源来解释它。CROSS JOIN显然执行笛卡尔联接,所以看起来这可能会做不必要的工作,或者执行效果不佳?谁能解释?
Wintron 2014年

仅当没有USING子句时,它才会做笛卡尔乘积。由于USING产品仅限于在id列中具有相同值的对,因此实际上非常有限。
Mchl 2014年

您可以使用内部联接做同样的事情吗?IEDELETE p1 FROM posts AS p1 INNER JOIN ( SELECT ID FROM posts GROUP BY id HAVING COUNT(id) > 1 ) AS p2 ON p2.ID=p1.ID
Kodos Johnson

1
@安德鲁:是的。这些连接在功能上完全相同。
Mchl '16

5

您可以使用内部联接:

DELETE 
    ps 
FROM 
    posts ps INNER JOIN 
         (SELECT 
           distinct id 
         FROM 
             posts 
         GROUP BY id  
      HAVING COUNT(id) > 1 ) dubids on dubids.id = ps.id  

0

如果要删除所有重复项,但要删除每组重复项中的一个,则这是一种解决方案:

DELETE posts
FROM posts
LEFT JOIN (
    SELECT id
    FROM posts
    GROUP BY id
    HAVING COUNT(id) = 1

    UNION

    SELECT id
    FROM posts
    GROUP BY id
    HAVING COUNT(id) != 1
) AS duplicate USING (id)
WHERE duplicate.id IS NULL;
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.