SQL查询每个唯一ID对应最早日期首条事件记录的方法
问题根因
你原有SQL无法得到预期结果的核心原因有两点:
- 分组粒度设置错误:
GROUP BY同时指定了unique_id、issue、date_event、age_at_event四个字段,只要四个字段任意一个值存在差异就会生成独立分组,自然无法按unique_id维度归并同一个人的所有记录 - 聚合逻辑无效:
least(min(date_event), min(date_event))属于冗余计算,对两个完全相同的最小值取较小值没有实际作用;同时分组查询中直接写SELECT *属于不规范写法,在开启严格SQL模式的引擎中会直接报错,即使能执行也会返回非分组字段的随机值,无法保证匹配到最早事件对应的完整行。
可行实现方案
以下两种写法覆盖绝大多数SQL使用场景,你可以根据自己用的数据库引擎选择:
方案1:窗口函数实现(推荐,适配MySQL8.0+、PostgreSQL、Hive、Spark SQL等绝大多数主流引擎)
通过窗口函数按人员分区,按事件时间升序打排名,取排名为1的记录即可:
SELECT * FROM ( SELECT *, ROW_NUMBER() OVER ( PARTITION BY unique_id ORDER BY date_event ASC ) AS record_rank FROM your_table ) ranked WHERE record_rank = 1;
如果你需要保留同一人员在最早事件时间点的所有重复记录(比如样例中unique_id=1234有两条完全一致的2016-04-01记录),可以将
ROW_NUMBER()替换为RANK(),不会遗漏同时间的首条重复数据。
基于你给出的样例数据,该语句返回结果如下:
- unique_id:1234, issue:issue_a, date_event:2016-04-01T00:00:00, age_at_event:6
- unique_id:5678, issue:issue_a, date_event:2019-09-01T00:00:00, age_at_event:2
- unique_id:65431, issue:issue_c, date_event:2019-09-01T00:00:00, age_at_event:1
方案2:子查询关联实现(适配不支持窗口函数的旧版数据库,如MySQL5.x)
先聚合出每个人员对应的最早事件时间,再关联原表匹配到对应时间的完整记录:
SELECT t1.* FROM your_table t1 INNER JOIN ( SELECT unique_id, MIN(date_event) AS first_event_time FROM your_table GROUP BY unique_id ) t2 ON t1.unique_id = t2.unique_id AND t1.date_event = t2.first_event_time;
内容的提问来源于stack exchange,提问作者Raven52
相关产品推荐
相关产品推荐

