题目
手写 SQL:删除表中重复的数据,只保留其中一条记录
答案
假设有一个表名为 `user`,包含以下列: | Column Name | Data Type | | ----------- | --------- | | id | int | | name | varchar | | age | int | | email | varchar | 下面是一个示例的 `user` 表: | id | name | age | email | | ---- | ------- | ---- | ------------------------------------------------- | | 1 | Alice | 25 | [alice@example.com](mailto:alice@example.com) | | 2 | Bob | 30 | [bob@example.com](mailto:bob@example.com) | | 3 | Charlie | 25 | [charlie@example.com](mailto:charlie@example.com) | | 4 | David | 30 | [david@example.com](mailto:david@example.com) | | 5 | Alice | 25 | [alice@example.com](mailto:alice@example.com) | 如果我们想要删除重复数据,也就是`name`、`age`、`email` 三列都相同的行,很多同学都会写出如下所示的 SQL: ```sql DELETE FROM user WHERE id NOT IN ( SELECT MIN(id) FROM user GROUP BY name, age, email ) ``` 但注意,这个 SQL 是无法执行成功的!因为**涉及到正在被查询的表的同时修改**,换句话说**在同一个表中进行 DELETE 操作的子查询会导致 SQL 语句执行失败**。 正确的方法应该是使用临时表,而不是直接在同一个表上进行 DELETE 操作: ```sql DELETE FROM user WHERE id NOT IN ( SELECT id FROM ( SELECT MIN(id) as id FROM user GROUP BY name, age, email ) AS t ); ``` 这个SQL语句中,内部的子查询会返回每组(name、age、email)中id最小的记录的集合,外部的DELETE语句会删除不在这个集合中的记录。这样就能够实现删除重复记录的目的,而且避免了在同一个表上同时查询和 DELETE。 执行完上述 SQL 语句后,表 `students` 中仅剩下如下数据: | id | name | age | | ---- | ------- | ---- | | 1 | Alice | 18 | | 2 | Bob | 19 | | 3 | Charlie | 20 | | 4 | David | 21 | 其中,原来 `id` 值为 5 的那条记录被删除了。