优化考勤表:删除员工每日冗余打卡记录的SQL问题
解决absen表每日员工打卡记录优化问题
问题根源
你当前的查询仅按IDkaryawan分组,计算的是该员工所有打卡记录中的全局最早/最晚时间,而非按日期拆分的每日极值,这就是批量员工数据时出错的核心原因。
核心修正思路
必须按员工ID + 打卡日期双重分组,确保每个员工的每日打卡记录独立计算上下班时间。
方案1:简洁聚合查询(仅需核心上下班时间)
如果只需要员工ID、日期、Clock In和Clock Out这几个核心字段,直接用聚合函数+日期分组即可:
MySQL / PostgreSQL
SELECT IDkaryawan, DATE(jam) AS tanggal, MIN(jam) AS clock_in, MAX(jam) AS clock_out FROM absen GROUP BY IDkaryawan, DATE(jam) ORDER BY IDkaryawan, tanggal;
SQL Server
SELECT IDkaryawan, CAST(jam AS DATE) AS tanggal, MIN(jam) AS clock_in, MAX(jam) AS clock_out FROM absen GROUP BY IDkaryawan, CAST(jam AS DATE) ORDER BY IDkaryawan, tanggal;
方案2:保留完整打卡记录(需原表全部字段)
如果需要保留打卡记录的其他字段(比如打卡设备、状态标记等),可以用窗口函数筛选每日的最早/最晚记录:
MySQL 8.0+ / PostgreSQL / SQL Server
WITH ranked_records AS ( SELECT *, -- 标记每日最早打卡(Clock In) ROW_NUMBER() OVER ( PARTITION BY IDkaryawan, DATE(jam) ORDER BY jam ASC ) AS rn_clock_in, -- 标记每日最晚打卡(Clock Out) ROW_NUMBER() OVER ( PARTITION BY IDkaryawan, DATE(jam) ORDER BY jam DESC ) AS rn_clock_out FROM absen ) SELECT IDkaryawan, DATE(jam) AS tanggal, jam AS record_time, CASE rn_clock_in WHEN 1 THEN 'Clock In' ELSE 'Clock Out' END AS record_type -- 此处可添加原表其他需要保留的字段 FROM ranked_records WHERE rn_clock_in = 1 OR rn_clock_out = 1 ORDER BY IDkaryawan, tanggal, record_time;
效果验证
比如某员工2024-05-20有3次打卡:2024-05-20 08:00:00、2024-05-20 12:30:00、2024-05-20 18:00:00,上述查询会返回:
- 方案1:一行记录,
clock_in=08:00:00,clock_out=18:00:00 - 方案2:两行记录,分别对应08:00的Clock In和18:00的Clock Out
内容的提问来源于stack exchange,提问作者unlimited system
相关产品推荐
相关产品推荐

