MySQL 使用 DELETE FROM 删除重复行

MySQL use DELETE FROM to remove duplicates rows

我正在学习 MySQL,今天我尝试解决一个关于 leetcode 的 MySQL 问题:https://leetcode.com/problems/delete-duplicate-emails/solution/

+----+------------------+
| Id | Email            |
+----+------------------+
| 1  | john@example.com |
| 2  | bob@example.com  |
| 3  | john@example.com |
+----+------------------+
Id is the primary key column for this table.

基本思路是从 table 中删除重复的行,只保留 ID 最小的行。预期结果:

+----+------------------+
| Id | Email            |
+----+------------------+
| 1  | john@example.com |
| 2  | bob@example.com  |
+----+------------------+

解决方法是

DELETE p1 FROM Person p1,Person p2 
WHERE
p1.Email = p2.Email AND p1.Id > p2.Id

我自己尝试了第二个测试用例:

+----+------------------+
| Id | Email            |
+----+------------------+
| 1  | john@example.com |
| 2  | bob@example.com  |
| 3  | john@example.com |
| 4  | john@example.com |
+----+------------------+

输出为:

+----+------------------+
| Id | Email            |
+----+------------------+
| 1  | john@example.com |
| 2  | bob@example.com  |
+----+------------------+

我不明白为什么条件 p1.Id > p2.Id 只保留具有最小 id 的行,因为我认为它只排除较小的行,它不适用于 重复次数超过 2 次的情况,对吗?但是正如第二个测试用例所示,它确实有效。 我认为这是因为

的语法
DELETE Table1
FROM Table1
INNER JOIN Table2 ON Table1.ID = Table2.ID

这究竟是如何工作的?有哪位大侠能给我解释一下吗,谢谢!

所以我想我自己找到了原因。这里的 DELETE 与普通的 DELETE 语句不完全一样

DELETE
FROM TABLE
WHERE conditions

而是

DELETE T1, T2
FROM T1
INNER JOIN T2 ON T1.key = T2.key
WHERE condition;

它通常被称为 MySQL DELETE JOIN statement,这就是它的工作原理。

更多详情https://www.mysqltutorial.org/mysql-delete-join/

这取决于你想删除什么 尝试将您的查询更改为

DELETE p2 FROM Person p1,Person p2 
  WHERE
p1.Email = p2.Email AND p1.Id > p2.Id

你会看到不同的结果

如果您为此尝试 SELECT 语句(同时删除 WHERE p1 > p2

    SELECT p1.*, p2.*, CASE WHEN p1.Id > p2.Id THEN 1 ELSE 0 END
    FROM Person p1,Person p2 
    WHERE p1.Email = p2.Email

您可以检查条件语句的值。 ID 3和4满足条件,则在table.

中删除

enter image description here

我建议您在调试脚本时对 JOIN 的 UPDATE 和 INSERT 操作执行相同的操作以查看数据的外观。

我建议这样表述查询:

delete t
from mytable t
inner join (select email, min(id) as min_id from mytable group by email) t1
    on t.email = t1.email and t.id > t1.min_id

这将加入自 table 反对 returns 每个 email 的最小值 id 的聚合查询。为什么我建议这是每行只匹配一次,而不是没有聚合的自连接方法,如果给定的电子邮件有超过 2 个重复项,最终会多次删除同一行。在这方面,上述查询更有效,而且更安全。

首先,这是一种非常糟糕的代码实现方式。但我想一分钱一分货。

其次,简单地 运行 查询作为 select:

SELECT p1.*, p2.*
FROM Person p1 JOIN
     Person p2 
     ON p1.Email = p2.Email AND p1.Id > p2.Id;

(请注意,我已将逻辑重写为 JOIN。您应该 始终 使用正确的、明确的、标准, 可读 JOIN 语法,但这两种方法在功能上是等价的。)

在你的第二个例子中,这个查询的结果是:

table1 email     table1 id    table2 id
john@example.com.    2            1
john@example.com.    3            1
john@example.com.    3            2

值得注意的是 id = 1 永远不会出现在第二列中——这是确定删除哪些 ID 的列。换句话说,除了每封电子邮件的最小 ID 外,其他所有 ID 都会被删除,因为有一个更小的 id.

这也暗示了为什么这是一个非常糟糕的解决方案。 MySQL 必须处理 id = 3 的两行。也许它试图同时删除两者。也许它只需要处理额外的数据。无论哪种方式,都有额外的工作。数据中包含相同电子邮件的行越多,创建的重复项就越多。

另一种方法,例如:

delete p
    from person p join
         (select email, min(id) as min_id
          from person p2
          group by email
         ) p2
         on p.email = p2.email and p.id > p2.min_id;

没有这个问题,在我看来,意图更明确。