技术求助:编写SQL查询获取每日用户最新签到记录(同一用户当日仅保留最新)
解决方案:获取每日用户最新签到记录
这个需求很常见,咱们可以用窗口函数或者关联子查询来实现,下面分别给出两种常用方案,你可以根据自己使用的数据库版本选择。
方案一:使用ROW_NUMBER()窗口函数(推荐)
这是最直观且高效的方法,适用于支持窗口函数的数据库(如MySQL 8.0+、PostgreSQL、SQL Server等)。
代码实现
SELECT CAST(checkin_datetime AS DATE) AS date, user_id, office_id FROM ( SELECT *, -- 按用户+日期分组,每组内按签到时间倒序编号 ROW_NUMBER() OVER ( PARTITION BY user_id, CAST(checkin_datetime AS DATE) ORDER BY checkin_datetime DESC ) AS rn FROM CHECKIN_TABLE ) t -- 只取每组的第一条(即最新的签到记录) WHERE rn = 1 -- 按日期和用户ID排序,让结果更规整 ORDER BY date, user_id;
逻辑说明
- 内层子查询中,
PARTITION BY user_id, CAST(checkin_datetime AS DATE)会把数据按「用户ID+签到日期」分成多个独立的组; ORDER BY checkin_datetime DESC让每个组内的记录按签到时间从晚到早排序,最新的记录会被标记为rn=1;- 外层查询筛选出
rn=1的记录,就是每个用户当天的最新签到。
用你提供的测试数据运行这段代码,会得到完全符合预期的结果:
date | user_id | office_id
2020-12-02 | 1 | D02
2020-12-02 | 2 | D01
2020-12-03 | 1 | D01
方案二:关联子查询(兼容老版本数据库)
如果你的数据库不支持窗口函数(比如MySQL 5.x),可以用这种方法来实现:
代码实现
SELECT CAST(c1.checkin_datetime AS DATE) AS date, c1.user_id, c1.office_id FROM CHECKIN_TABLE c1 LEFT JOIN CHECKIN_TABLE c2 ON c1.user_id = c2.user_id AND CAST(c1.checkin_datetime AS DATE) = CAST(c2.checkin_datetime AS DATE) AND c1.checkin_datetime < c2.checkin_datetime -- 找不到比当前记录更晚的签到,说明这就是当天最新的 WHERE c2.id IS NULL ORDER BY date, user_id;
逻辑说明
通过左连接,给每条记录匹配同一个用户、同一天内签到时间更晚的记录。如果匹配不到(c2.id IS NULL),就说明这条记录是该用户当天的最后一次签到。
内容的提问来源于stack exchange,提问作者Najwan
相关产品推荐
相关产品推荐

