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 值为 2
和 3
.
的行
首先,这是使用聚合更常见的写法:
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 需要弄清楚当你说要删除一条记录四次时该怎么办。 (当然,它做了正确的事情,但还有额外的工作。)
聚合方式不存在此类问题
假设我有以下 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 值为 2
和 3
.
首先,这是使用聚合更常见的写法:
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 需要弄清楚当你说要删除一条记录四次时该怎么办。 (当然,它做了正确的事情,但还有额外的工作。)
聚合方式不存在此类问题