MySQL去重查询,只留一条最新的数据
引言
在日常的数据库操作中,经常会碰到需要对数据进行去重查询的情况,特别是在处理大量数据时,保证数据的唯一性是非常重要的。在MySQL中,我们可以使用不同的方法来实现去重查询,本文将详细介绍几种常用的方法,并给出示例代码和运行结果。
背景
在实际的应用中,我们经常会遇到数据库表中存在重复数据的情况。这种情况可能是由于数据导入、人为操作错误、程序错误等原因引起。为了保证数据的完整性和一致性,我们需要对重复数据进行去重操作。
假设我们有如下的一个示例数据表students
,其中包含了学生的姓名(name
)、年龄(age
)和加入日期(join_date
)三个字段:
CREATE TABLE students (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
age INT NOT NULL,
join_date DATE NOT NULL
);
INSERT INTO students (name, age, join_date)
VALUES ('张三', 20, '2020-01-01'),
('李四', 22, '2020-01-01'),
('张三', 20, '2020-02-01'),
('王五', 18, '2020-03-01'),
('李四', 22, '2020-04-01'),
('张三', 21, '2020-05-01');
在上述示例数据表中可以看到,存在姓名、年龄和加入日期完全相同的重复数据。
我们的目标是,针对重复数据,只保留每个姓名的最新的一条数据,即只保留join_date
最大的一条记录。
方法一:使用子查询和GROUP BY
一种常用的方法是使用子查询和GROUP BY语句来实现去重查询。具体步骤如下:
- 编写子查询,选择每个姓名对应的最大的加入日期。
SELECT name, MAX(join_date) AS max_date FROM students GROUP BY name;
运行结果如下:
name | max_date |
---|---|
张三 | 2020-05-01 |
李四 | 2020-04-01 |
王五 | 2020-03-01 |
-
将上述子查询作为临时表,在原表中进行连接查询,找出对应的记录。
SELECT s.* FROM students s INNER JOIN ( SELECT name, MAX(join_date) AS max_date FROM students GROUP BY name ) t ON s.name = t.name AND s.join_date = t.max_date;
运行结果如下:
id | name | age | join_date |
---|---|---|---|
6 | 张三 | 21 | 2020-05-01 |
5 | 李四 | 22 | 2020-04-01 |
4 | 王五 | 18 | 2020-03-01 |
通过上述方法,我们成功地实现了去重查询,只保留了每个姓名的最新的一条记录。
方法二:使用窗口函数
MySQL 8.0引入了窗口函数(Window Functions)的概念,可以方便地实现类似的需求。
具体步骤如下:
- 使用窗口函数
ROW_NUMBER()
为每个姓名分配一个序号,按照加入日期降序排列。SELECT id, name, age, join_date, ROW_NUMBER() OVER (PARTITION BY name ORDER BY join_date DESC) AS rn FROM students;
运行结果如下:
id | name | age | join_date | rn |
---|---|---|---|---|
6 | 张三 | 21 | 2020-05-01 | 1 |
3 | 张三 | 20 | 2020-02-01 | 2 |
1 | 张三 | 20 | 2020-01-01 | 3 |
5 | 李四 | 22 | 2020-04-01 | 1 |
2 | 李四 | 22 | 2020-01-01 | 2 |
4 | 王五 | 18 | 2020-03-01 | 1 |
-
在上述结果中选取序号为1的记录。
SELECT id, name, age, join_date FROM ( SELECT id, name, age, join_date, ROW_NUMBER() OVER (PARTITION BY name ORDER BY join_date DESC) AS rn FROM students ) t WHERE rn = 1;
运行结果如下:
id | name | age | join_date |
---|---|---|---|
6 | 张三 | 21 | 2020-05-01 |
5 | 李四 | 22 | 2020-04-01 |
4 | 王五 | 18 | 2020-03-01 |
通过使用窗口函数,我们同样可以达到与方法一相同的效果,只保留了每个姓名的最新的一条记录。
方法三:使用临时表和LIMIT
另一种方法是使用临时表和LIMIT语句来实现去重查询。具体步骤如下:
- 创建临时表
t_stu
,保存每个姓名对应的最新的一条记录。CREATE TEMPORARY TABLE t_stu SELECT id, name, age, join_date FROM students GROUP BY name HAVING join_date = MAX(join_date);
- 查询临时表中的数据。
SELECT * FROM t_stu;
运行结果如下:
id | name | age | join_date |
---|---|---|---|
6 | 张三 | 21 | 2020-05-01 |
5 | 李四 | 22 | 2020-04-01 |
4 | 王五 | 18 | 2020-03-01 |
通过创建临时表和使用LIMIT语句,我们同样成功地实现了去重查询,只保留了每个姓名的最新的一条记录。
总结
本文介绍了三种常用的方法来实现MySQL去重查询,只保留最新的一条记录。这些方法包括使用子查询和GROUP BY、使用窗口函数以及使用临时表和LIMIT语句。根据实际情况选择合适的方法可以提高查询性能和数据的完整性。