订阅更新

删除重复邮箱:只保留 Id 最小的一条

SQL 实战 123 题 · 第 11 题 简单 约 2 分钟读完

LeetCode 196 · DELETE 自连接、去重保留规则

本文目录
  1. 面试怎么回答
  2. 题意
  3. 表结构
  4. 思路
  5. 参考解法
  6. 易错点

面试怎么回答

我会用自连接的多表 DELETE:Person p1 和 p2 按邮箱相等关联,删除 p1.Id > p2.Id 的行,留下的就是每个邮箱的最小 Id。真实业务去重我会先在临时表里用 ROW_NUMBER 标记要删的行,核对数量后再删,并保留可回滚的备份。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

题意

直接修改人员表:同一个邮箱出现多次时,只保留 Id 最小的那一行,其余删除。

表结构

  • Person:Id(主键)、Email

思路

用多表 DELETE 的自连接:把表关联自己,邮箱相同且 Id 更大的那一份就是要删除的重复行。也可以先算出每个邮箱的最小 Id,再删除不在其中的行,但 MySQL 不允许在 DELETE 的子查询里直接引用正在删除的表,需要多包一层派生表。

参考解法

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

另一种写法:先算每个邮箱的最小 Id,再删其余行(注意外面多包一层)

DELETE FROM Person
WHERE Id NOT IN (
  SELECT id FROM (SELECT MIN(Id) AS id FROM Person GROUP BY Email) t
)

易错点

  • MySQL 里 DELETE FROM Person WHERE Id NOT IN (SELECT MIN(Id) FROM Person GROUP BY Email) 会报错,要把子查询再包一层。
  • 这是修改数据的操作,生产环境要先 SELECT 出将被删除的行确认一遍,或者在备份表上执行。
刷题进度保存在当前浏览器