题目描述

(通过次数171,917 | 提交次数252,097,通过率68.19%)

表:Person
+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| id          | int     |
| email       | varchar |
+-------------+---------+
id是该表的主键列。
该表的每一行包含一封电子邮件。电子邮件将不包含大写字母。

编写一个 SQL 删除语句来 删除 所有重复的电子邮件,只保留一个id最小的唯一电子邮件。
以 任意顺序 返回结果表。(注意:仅需要写删除语句,将自动对剩余结果进行查询)
查询结果格式如下所示。

示例 1:
输入: 
Person 表:
+----+------------------+
| id | email            |
+----+------------------+
| 1  | john@example.com |
| 2  | bob@example.com  |
| 3  | john@example.com |
+----+------------------+
输出: 
+----+------------------+
| id | email            |
+----+------------------+
| 1  | john@example.com |
| 2  | bob@example.com  |
+----+------------------+
解释: john@example.com重复两次。我们保留最小的Id = 1。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/delete-duplicate-emails
//测试数据
Create table If Not Exists Person (Id int, Email varchar(255));

insert into Person (id, email) values ('1', 'john@example.com');
insert into Person (id, email) values ('2', 'bob@example.com');
insert into Person (id, email) values ('3', 'john@example.com');

解题思路

这是一道关于delete操作题目。

对于MySQL数据库来说,学习delete操作,看这一篇就够了。

Person表中主键为id,但存在多个id对应同一个email的情况。题目要求:相同的email,只保留一条记录,即id值最小的那条。

那么,可以通过如下步骤来实现:

**第一步**:得出每个email对应的最小id;

**第二步**:删除除第一步结果中id值的其他所有行;

对于第一步,是一个分组取最小值的典型操作,使用group by + min函数或者开窗函数,都可以很简单的实现。

对于第二步,首先是个删除操作,那么就需要使用delete关键字。然后使用排除操作,把需要的行留下,不需要的行删除即可。

在sql语言中,排除操作可以使用not in或not exists来完成。可以参考下面的方法一和方法二。

这里,强哥比较推荐第三种方法:自关联。

首先,使用自关联对email相同的行两两组合;然后,使用比较运算符把大于待删除表中id的值的行全部删除。这种方法,在表中数据量较大时,有较好的性能表现。详细写法可以参考下面的方法三。

参考SQL

未特别说明的情况下,参考SQL为基于MySQL8.0实现。
--方法一
delete from Person
where id not in (
    select * from (
        select min(b.id) from Person b group by b.email
    ) as a
);

--方法二
delete from Person as a
where not exists (
    select 1 from (
        select min(b.id) as min_id from Person b group by b.email
    ) as c
    where a.id = c.min_id
);

--方法三
delete a 
from Person as a
inner join Person as b
on a.email = b.email
and a.id > b.id;
picture loss