Article / 文章

LeetCode 第196题:删除重复的电子邮箱

编写一个 SQL 查询,删除 Person 表中所有重复的电子邮箱,重复的邮箱里只保留 Id 最小 的那个。

题目描述

编写一个 SQL 查询,删除 Person 表中所有重复的电子邮箱,重复的邮箱里只保留 Id 最小 的那个。

难度

简单

题目链接

点击在LeetCode中查看题目

示例

示例:

+----+------------------+
| Id | Email            |
+----+------------------+
| 1  | john@example.com |
| 2  | bob@example.com  |
| 3  | john@example.com |
+----+------------------+
Id 是这个表的主键。

例如,在运行你的查询语句之后,上面的 Person 表应返回以下行:

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

解题思路

方法一:使用DELETE和子查询

我们可以使用DELETE语句配合子查询来删除重复的邮箱,只保留Id最小的记录。

关键点:

  1. 使用子查询找出每个邮箱对应的最小Id
  2. 删除不在最小Id列表中的记录
  3. 使用自连接来比较Id

时间复杂度:O(n²),其中n是表中的记录数 空间复杂度:O(n),需要存储子查询的结果

方法二:使用DELETE和临时表

这种方法先创建一个临时表存储要保留的记录,然后删除不在临时表中的记录。

关键点:

  1. 使用GROUP BY和MIN(Id)找出每个邮箱对应的最小Id
  2. 创建临时表存储这些记录
  3. 删除不在临时表中的记录

时间复杂度:O(n log n),其中n是表中的记录数 空间复杂度:O(n),需要存储临时表

方法三:使用DELETE和EXISTS

这种方法使用EXISTS子查询来找出需要删除的记录。

关键点:

  1. 使用EXISTS检查是否存在更小的Id
  2. 如果存在更小的Id,则删除当前记录
  3. 使用自连接来比较Id

时间复杂度:O(n²),其中n是表中的记录数 空间复杂度:O(1),不需要额外空间

代码实现

方法一:使用DELETE和子查询

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

方法二:使用DELETE和临时表

DELETE FROM Person
WHERE Id NOT IN (
    SELECT MIN(Id)
    FROM Person
    GROUP BY Email
);

方法三:使用DELETE和EXISTS

DELETE FROM Person p1
WHERE EXISTS (
    SELECT 1 FROM Person p2
    WHERE p2.Email = p1.Email AND p2.Id < p1.Id
);

性能分析

各方法的性能对比:

方法 执行用时 内存消耗 特点
方法一 0 ms 3.0 MB 自连接方式,直观高效
方法二 4 ms 3.2 MB 使用临时表,适合大数据量
方法三 8 ms 3.1 MB EXISTS子查询,逻辑清晰

补充说明

代码亮点

  1. 方法一使用自连接,代码简洁高效
  2. 方法二使用临时表,适合处理大数据量
  3. 方法三使用EXISTS,逻辑清晰易懂

SQL语句解释

  • DELETE p1 FROM Person p1, Person p2:使用自连接进行删除操作
  • GROUP BY Email:按邮箱分组
  • MIN(Id):获取每组中Id最小的记录
  • EXISTS:检查是否存在满足条件的记录

常见错误

  1. 没有正确处理NULL值的情况
  2. 删除条件写反,导致删除了需要保留的记录
  3. 没有考虑表为空的情况
  4. 使用IN子查询时没有处理NULL值

相关题目