原题题目
表:
Person
+-------------+---------+ | Column Name | Type | +-------------+---------+ | id | int | | email | varchar | +-------------+---------+ id 是该表的主键列(具有唯一值的列)。 该表的每一行包含一封电子邮件。电子邮件将不包含大写字母。编写解决方案 删除 所有重复的电子邮件,只保留一个具有最小
id
的唯一电子邮件。(对于 SQL 用户,请注意你应该编写一个
DELETE
语句而不是SELECT
语句。)运行脚本后,显示的答案是
Person
表。驱动程序将首先编译并运行您的代码片段,然后再显示Person
表。Person
表的最终顺序 无关紧要 。返回结果格式如下示例所示。
示例 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。
方法一 分组
先对邮箱进行分组,然后查找邮箱最小id,形成一个子查询。
遍历表格,如果id不在子查询结果里,则删除。
注意:
1、这段代码在leetcode系统上可行,但是在本地运行中可能会报错1175,解决方法是解除安全模式,具体参考 MySQL报错之1175和1093-CSDN博客
2、这里在子查询外层再嵌套一个查询,因为不能同时对一个表执行子查询后再执行删除操作。否则会报错1093,具体参考 MySQL报错之1175和1093-CSDN博客
delete from Person where id not in
(select * from (select min(t1.id)
from Person as t1
group by t1.email) a);
方法二 窗口函数
用row_number(),按id升序,序号>1的就是重复且id较大的
注意事项与方法二一致
delete from Person
where id not in (
select id
from (select *,row_number() over(partition by email order by id) rowNumber
from Person) a
where rowNumber = 1
)
方法三 自连接
注意:在leetcode上成功运行,但是在本地mysql报错1175,解决方法是解除安全模式
DELETE p1 FROM Person p1,
Person p2
WHERE
p1.Email = p2.Email AND p1.Id > p2.Id
方法四 临时表实现分组
临时表解决安全模式(1175报错)和同时对一张表进行删除和查询操作(1093报错)
注意:此方法只能在本地mysql上运行,而在leetcode上执行报错
-- 第一步:创建临时表存储要删除的 id
CREATE TEMPORARY TABLE temp_to_delete (id INT);
-- 第二步:将要删除的 id 插入到临时表中
INSERT INTO temp_to_delete (id)
SELECT id
FROM Person
WHERE id NOT IN (
SELECT MIN(id)
FROM Person
GROUP BY email
);
-- 第三步:使用临时表删除记录
DELETE FROM Person
WHERE id IN (SELECT id FROM temp_to_delete);
-- 第四步:删除临时表
DROP TEMPORARY TABLE temp_to_delete;