SQL新手求助:将考勤打卡记录表转换为上下班时间格式的查询语句
解决考勤数据行转列的SQL查询方案
嘿,作为SQL新手碰到这种把多行打卡记录合并成一行的需求太常见啦,我来一步步帮你实现想要的结果~
首先看你的原始数据,每个员工每天有两条打卡记录:一条上班时间,一条下班时间。我们的目标就是把同一天的两条记录合并,分别提取出上班(ATTINTIME)和下班(ATTOUTTIME)时间。
方法一:用聚合函数(最适合你的场景)
因为你每天只有两次打卡,直接用MIN()取最早的时间作为上班,MAX()取最晚的时间作为下班就可以了,配合GROUP BY按员工和日期分组:
SELECT EMP_NUMBER, ATTDATE, MIN(ATTTIME) AS ATTINTIME, MAX(ATTTIME) AS ATTOUTTIME FROM 你的考勤表名 GROUP BY EMP_NUMBER, ATTDATE;
解释:
GROUP BY EMP_NUMBER, ATTDATE把数据按员工+日期分组,确保每个组里是同一个人同一天的所有打卡记录MIN(ATTTIME)找出组里最早的打卡时间,也就是上班时间MAX(ATTTIME)找出组里最晚的打卡时间,也就是下班时间
方法二:用窗口函数(应对更复杂的打卡场景)
如果某天员工有多次打卡(比如中途外出又返回),你需要明确区分第一次和第二次打卡的话,可以用ROW_NUMBER()窗口函数给每条记录排序,再通过条件筛选提取:
WITH RankedAttendance AS ( SELECT EMP_NUMBER, ATTDATE, ATTTIME, ROW_NUMBER() OVER (PARTITION BY EMP_NUMBER, ATTDATE ORDER BY ATTTIME) AS rn FROM 你的考勤表名 ) SELECT EMP_NUMBER, ATTDATE, MAX(CASE WHEN rn = 1 THEN ATTTIME END) AS ATTINTIME, MAX(CASE WHEN rn = 2 THEN ATTTIME END) AS ATTOUTTIME FROM RankedAttendance GROUP BY EMP_NUMBER, ATTDATE;
解释:
- 先通过CTE给每个员工每天的打卡记录按时间排序,
rn=1是最早的打卡,rn=2是第二次打卡 - 然后用
CASE WHEN配合MAX()把不同排序的时间放到对应的列里
把上面的你的考勤表名替换成你实际的表名,就能得到你想要的结果啦~
内容的提问来源于stack exchange,提问作者Nivas Gupta




