如何从 MySQL 中的选择中删除?
Posted
技术标签:
【中文标题】如何从 MySQL 中的选择中删除?【英文标题】:How to delete from select in MySQL? 【发布时间】:2011-06-01 13:23:42 【问题描述】:此代码不适用于 mysql 5.0,如何重写以使其工作
DELETE FROM posts where id=(SELECT id FROM posts GROUP BY id HAVING ( COUNT(id) > 1 ))
我想删除没有唯一 ID 的列。我会补充一点,大多数时候它只有一个 id(我尝试了 in 语法,但它也不起作用)。
【问题讨论】:
【参考方案1】:SELECT
(子)查询返回结果集合。所以你需要在WHERE
子句中使用IN
,而不是=
。
此外,如this answer 所示,您不能从同一查询中的子查询修改同一表。但是,您可以在单独的查询中使用SELECT
然后DELETE
,或者嵌套另一个子查询并为内部子查询结果设置别名(虽然看起来很hacky):
DELETE FROM posts WHERE id IN (
SELECT * FROM (
SELECT id FROM posts GROUP BY id HAVING ( COUNT(id) > 1 )
) AS p
)
或者使用连接as suggested by Mchl。
【讨论】:
我有一个包含 150 个重复键的表。我执行了上面的查询,它说“144行受影响”,但那里仍然有重复的键。所以我再次执行查询,它说 5 行受影响,再次:1 行受影响。然后所有重复的键都消失了。这是为什么呢? 发生这种情况,因为您只从每组重复项中删除 1 个条目:SELECT id FROM posts GROUP BY id HAVING ( COUNT(id) > 1 )
#1248 - 每个派生表都必须有自己的别名
@thang:这就是我说给内部子查询起别名的原因。
请您解释一下“As p”是做什么的?【参考方案2】:
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
显然执行了笛卡尔连接,所以看起来这可能会做不必要的工作,或者表现不佳?谁能解释一下?
只有在没有USING
子句的情况下才会进行笛卡尔积。对于USING
,产品仅限于id
列中具有相同值的对,因此实际上非常有限。
你能用内部连接做同样的事情吗? IE。 DELETE 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
@Andrew:是的。从功能上讲,这些连接完全相同。【参考方案3】:
你可以使用内连接:
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
【讨论】:
【参考方案4】:如果您想删除所有重复项,但要删除每组重复项中的一个,这是一种解决方案:
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;
【讨论】:
以上是关于如何从 MySQL 中的选择中删除?的主要内容,如果未能解决你的问题,请参考以下文章