原题链接
有一张Person表:

编写一个SQL删除语句来删除所有重复的电子邮件,只保留一个id最小的唯一电子邮件。
首先,我们可以去考虑如何拿到每种邮件最小id值:那么我们就需要用到group by 邮件 以及min(id):
select min(p.id) as d_id from Person p group by p.email
结果如下(数据量大的话会更直观一点):

之那么既然我们要保留这个数据,那么删除的时候,只需要反过来即可。删除不在上述返回结果集中的数据即可,即not in:
DELETE from Person where id not in (select min(p.id) as d_id from Person p group by p.email)
但是这么写却有一个问题:

意思是不能先select出同一表中的某些值,再update这个表。即不能依据某字段值做判断再来更新某字段的值。
因此对于这种SQL,需要用到中间表来做查询,上述SQL修改为:
DELETE from Person where id not in (
select d_id from (
select min(p.id) as d_id from Person p group by p.email
) t1
)
自连接的方式很直白:
DELETE p1 FROM Person p1,
Person p2
WHERE
p1.email = p2.email AND p1.id > p2.id
意思是:删除p1表中的数据,需要删除的数据需要满足下面的条件。
p1表和p2表的数据的邮箱一致。p1表的id要大于p2表的id。那么以p1表中的第一条数据为例:

在p2表中没有符合条件的,因为id为1是最小的,因此该条数据不删除。

再以p1表中的第二条数据为例:

在p2表中依旧没有符合条件的。
以p1表中的第三条数据为例:

它的id比p2表中的第一条数据要大,并且邮箱相同,满足条件,删除。

最终结果:
# 方案一
DELETE from Person where id not in (
select d_id from (
select min(p.id) as d_id from Person p group by p.email
) t1
)
# 方案二
DELETE p1 FROM Person p1,
Person p2
WHERE
p1.email = p2.email AND p1.id > p2.id
知识点:不能依据某字段值做判断再来更新某字段的值。 伪代码表示就是:
update / delete xxx where 列 in ( select 列 where 条件)
这个时候需要运用中间表来做一次查询。