前言
Mysql查询:每个重复数据,只显示一条,通过使用 min(id)
实现是一个非常经典和高效的方法!这通常用于在有自增主键(如 id
)的表中,从重复数据中保留“最老”或“最早”插入的那一条记录。
下面我为您详细介绍如何使用 MIN(id)
来实现“每个重复数据只显示一条”。
场景假设
假设我们有一个用户表 users
,结构如下:
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50),
email VARCHAR(100),
age INT
);
表中有一些重复的 email
数据:
id | name | age | |
---|---|---|---|
1 | Alice | alice@email.com | 25 |
2 | Bob | bob@email.com | 30 |
3 | Alice | alice@email.com | 26 |
4 | Carol | carol@email.com | 28 |
5 | Bob | bob@email.com | 32 |
我们希望根据 email
字段去重,保留每个 email
对应的 id
最小的那条记录。
方法一:使用 MIN(id)
+ GROUP BY
(推荐用于查询)
如果您只是想查询去重后的数据(不修改原表),可以使用:
SELECT MIN(id) AS id, name, email, age
FROM users
GROUP BY email;
结果:
id | name | age | |
---|---|---|---|
1 | Alice | alice@email.com | 25 |
2 | Bob | bob@email.com | 30 |
4 | Carol | carol@email.com | 28 |
注意:这里有一个重要细节!虽然我们
GROUP BY email
,但name
和age
并不在GROUP BY
子句中。在 MySQL 的宽松模式下,这会返回每个分组中第一条遇到的记录的name
和age
。由于我们使用了MIN(id)
,通常第一条就是id
最小的那条,所以结果是正确的。但在 SQL 严格模式(如
ONLY_FULL_GROUP_BY
)下,这种写法会报错。更严谨的写法是结合子查询。
方法二:使用子查询(最严谨,推荐)
为了确保结果的准确性和兼容性,推荐使用子查询先找出每个 email
对应的最小 id
,然后再关联查询完整数据:
SELECT u.id, u.name, u.email, u.age
FROM users u
INNER JOIN (
SELECT email, MIN(id) AS min_id
FROM users
GROUP BY email
) t ON u.email = t.email AND u.id = t.min_id;
结果(同上):
id | name | age | |
---|---|---|---|
1 | Alice | alice@email.com | 25 |
2 | Bob | bob@email.com | 30 |
4 | Carol | carol@email.com | 28 |
优点:
- 逻辑清晰,结果准确。
- 兼容所有 SQL 模式。
- 可以轻松扩展到多字段去重。
方法三:删除重复数据(保留最小 id)
如果您想永久删除重复数据,只保留 id
最小的那条,可以使用:
DELETE u1 FROM users u1
INNER JOIN users u2
WHERE u1.email = u2.email
AND u1.id > u2.id;
这条语句的逻辑是:对于每一对具有相同 email
的记录,如果 u1
的 id
大于 u2
的 id
,就删除 u1
。最终只保留 id
最小的那条。
总结
MIN(id)
是一个非常实用的技巧,它利用了自增主键的特性来确定“第一条”记录。- 对于查询,推荐使用方法二(子查询),因为它最严谨。
- 对于删除重复数据,推荐使用方法三(自连接删除)。
- 您的想法“通过使用
min(id)
实现”完全正确,并且是数据库去重的最佳实践之一。👍
评论