MySQL 多列内连接

MySQL inner join with multiple columns

假设我有以下 table 称为 Email,其中 Id 是主键:

+----+------------------+
| Id | Email            |
+----+------------------+
| 1  | anne@example.com |
| 2  | cat@example.com  |
| 3  | anne@example.com |
+----+------------------+

我正在尝试删除除第一个以外的所有重复项。所以在这种情况下,所需的输出将是

+----+------------------+
| Id | Email            |
+----+------------------+
| 1  | anne@example.com |
| 2  | cat@example.com  |
+----+------------------+

问过朋友后,我发现这个解决方案有效:

DELETE t1 FROM Person t1 INNER JOIN Person t2
Where t1.Email=t2.Email and t1.Id > t2.Id

我的问题是为什么这样做有效?特别是,当 t1 inner join t2 on Email 字段时,程序如何知道 anne@example.com 的哪一行应该与哪一行匹配,因为这个有多次出现具有不同 ID 的值?

您比较两个相同的表并检查两个表的所有电子邮件地址相同的地方。

如果id相同,则该行被忽略。

如果 id 不同 并且它的 id 必须大于第一次出现的 id ,则此行将被删除.

考虑此 select 语句仅按电子邮件列之间的相等性进行过滤

SELECT t1.*, t2.* 
  FROM Person t1 
 INNER JOIN Person t2
 WHERE t1.Email=t2.Email 
 ORDER BY t1.Id, t2.Id;

returns (1,1), (1,3), (3,1), (3,3) 用于 t1.id 和 t2.id 值分别用于邮件 anne@example.com,只有 (2,2) 用于 cat@example.com.然后如果你考虑其他过滤器 AND t1.Id > t2.Id,

SELECT t1.*, t2.* 
  FROM Person t1 
 INNER JOIN Person t2
 WHERE t1.Email=t2.Email 
   AND t1.id > t2.id
 ORDER BY t1.Id, t2.Id;

那么你将只有一个元组 (3,1) 因为 t1.id > t2.id 只满足这种 id 元组的情况。如果您将 SELECT t1.*, t2.* 转换为 DELETE t1(当然也删除 ORDER BY 部分),那么显然您将删除 id = 3 并留下 ID 值为 1 的行和2,相反,如果您将 SELECT t1.*, t2.* 替换为 DELETE t2,那么您将拥有 ID 值为 23.

的行

Demo

首先,这是使用聚合更常见的写法:

DELETE p
    FROM Person p INNER JOIN
         (SELECT p2.email, MIN(p2.id) as min_id
          FROM Person p2
          GROUP BY p2.email
         ) p2
         ON p.email = p2.email and p.id > p2.min_id;

为什么你的版本有效?好吧,它之所以有效,是因为 join 不仅可以匹配数据,还可以过滤数据。

所以,条件

t1.Email = t2.Email and t1.Id > t2.Id

表示对于 t1 中的每条记录,在 t1.id > t2.id 的 t2 中找到匹配的记录。也就是说,在 t1 中查找具有 更小 id.

匹配记录的记录

所有记录都有这个 属性 -- 除了每个电子邮件一个。那将是具有最小 id 的记录。

我不推荐这种识别最小记录的方法,因为join会乘以记录数。如果一封电子邮件有五个记录,则其中一个记录最多有四个匹配项。 MySQL 需要弄清楚当你说要删除一条记录四次时该怎么办。 (当然,它做了正确的事情,但还有额外的工作。)

聚合方式不存在此类问题