MySQL中如何按时间排序获取各用户不同Email的首次出现记录
MySQL获取同一用户不同Email的首次出现记录
需求说明
需要筛选出每个用户下不同Email的首次出现记录(按时间升序排序后的第一条)。
原始表数据
| User | Time | ID | |
|---|---|---|---|
| David | 1 | 2012/01/19 | 1 |
| David | 2 | 2012/01/20 | 2 |
| David | 2 | 2012/01/21 | 1 |
| David | 2 | 2012/01/22 | 2 |
| David | 2 | 2012/01/23 | 1 |
| David | 3 | 2012/01/24 | 2 |
| David | 3 | 2012/01/25 | 1 |
| John | 1 | 2012/01/19 | 1 |
| John | 1 | 2012/01/20 | 2 |
| John | 1 | 2012/01/21 | 1 |
| John | 2 | 2012/01/22 | 2 |
| John | 2 | 2012/01/23 | 1 |
期望结果
| User | Time | ID | |
|---|---|---|---|
| David | 1 | 2012/01/19 | 1 |
| David | 2 | 2012/01/20 | 2 |
| David | 3 | 2012/01/24 | 2 |
| John | 1 | 2012/01/19 | 1 |
| John | 2 | 2012/01/22 | 2 |
遇到的问题
- 使用
DISTINCT无法满足需求,因为它会对整行数据去重,无法针对「用户+Email」组合筛选首次记录。 - 尝试过
ROW_NUMBER() OVER (PARTITION BY Email ORDER BY Time DESC) rnm,但分区仅按Email划分,会把不同用户的同一Email归为一组,导致结果错误:设置rnm = 1会遗漏其他用户的同Email记录,设置范围则返回重复数据。
解决方案
问题出在分区条件错误,应该按User和Email的组合进行分区,再按时间升序排序,取每组的第一条记录即可。
方法1:使用窗口函数(MySQL 8.0及以上版本)
SELECT User, Email, Time, ID FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY User, Email ORDER BY Time ASC) AS rn FROM your_table_name ) t WHERE rn = 1 ORDER BY User, Time;
- 解释:
PARTITION BY User, Email会把同一用户的同一Email分成一组,ORDER BY Time ASC确保每组内按时间升序排列,rn = 1就取每组的第一条(即首次出现)记录。
方法2:子查询+分组(兼容MySQL 5.x版本)
如果你的MySQL版本不支持窗口函数,可以用子查询先获取每个「用户+Email」组合的最小时间,再关联原表获取对应记录:
SELECT t1.* FROM your_table_name t1 INNER JOIN ( SELECT User, Email, MIN(Time) AS first_time FROM your_table_name GROUP BY User, Email ) t2 ON t1.User = t2.User AND t1.Email = t2.Email AND t1.Time = t2.first_time ORDER BY t1.User, t1.Time;
- 注意:如果同一「用户+Email+时间」有多个记录(即同一时间同一用户同一Email出现多条),这个方法会返回所有符合的记录。如果只需要其中一条,可以再配合
GROUP BY User, Email或使用LIMIT进一步筛选。
内容的提问来源于stack exchange,提问作者Yuchi
相关产品推荐
相关产品推荐

