文章目录
  1. 1. 题目
  2. 2. 解题思路
  3. 3. 注意事项
  4. 4. 构造测试数据
  5. 5. 一种答案

题目

#196 Delete Duplicate Emails

解题思路

奇怪的是这题标明难度是 EASY,但通过率却是倒数第三,看来不少人在这个坑栽跟头。那我们换个思路不直接想如何 DELETE 重复值,而是先 SELECT 出我们需要的,非重复 Email 和其对应的最小 Id,然后把原表格中其他的数据删掉。

注意事项

  • 不能在一个语句中既更改表中数据(DELETE/UPDATE)又在子查询语句中 SELECT 该表。例如这样是不允许的 DELETE FROM Person WHERE Id IN (SELECT Id FROM Person),会报错。

    有一个 trick,可以再加一层 SELECT 把这个结果变成一个临时表。那么 MySQL 就会先运行子查询语句生成临时表,这样就和你真正要 DELETE 的表不算同一个表了。

构造测试数据

1
2
3
4
5
6
7
8
9
10
CREATE TABLE Person (
Id INT,
Email VARCHAR(100)
);

DELETE FROM Person;
INSERT INTO Person VALUES
(1, 'john@example.com'),
(2, 'bob@example.com'),
(3, 'john@example.com');

预期运行后 Person 表数据:

Id Email
2 bob@example.com
1 john@example.com

一种答案

完整答案:

1
2
3
4
5
6
7
8
9
10
11
-- Runtime: 1070 ms
DELETE FROM Person
WHERE
Person.Id NOT IN (SELECT
minId
FROM
(SELECT
MIN(Id) AS minId, Email
FROM
Person
GROUP BY Email) AS tmp);

接着我们分步看,第一步是找出需要保留的行:

1
2
3
4
5
SELECT 
MIN(Id) AS minId, Email
FROM
Person
GROUP BY Email

运行结果,其实这就是我们想要的 Person 表的最终样子嘛

min(Id) Email
2 bob@example.com
1 john@example.com

第二步删除表中不是我们要保留的行(NOT IN),也就是重复值。但由于语法限制需要多一层 SELECT 来构建临时表 tmp。


本博客微信公众号

文章目录
  1. 1. 题目
  2. 2. 解题思路
  3. 3. 注意事项
  4. 4. 构造测试数据
  5. 5. 一种答案