MySQL补全clockInTest考勤后计算工时更新WorkDay表的实现问题
考勤统计更新SQL实现方案
实现逻辑
- 按
WorkDayId、EmployeeId分组,将同组内的有效打卡记录按时间戳排序,配对相邻的Start和End打卡 - 总工作时长计算:所有配对的
Start到对应End的秒级时间差之和乘以1000转毫秒 - 休息时长计算:所有配对的
End到下一个Start的秒级间隔之和乘以1000转毫秒,无间隔则返回0 - 关联
WorkDay表完成字段批量更新
适用范围
MySQL 8.0及以上版本(基于窗口函数实现打卡配对,性能更优)
UPDATE WorkDay w INNER JOIN ( SELECT WorkDayId, EmployeeId, SUM(TIMESTAMPDIFF(SECOND, start_time, end_time)) * 1000 AS TimeSpan, IFNULL(SUM(TIMESTAMPDIFF(SECOND, end_time, next_start)) * 1000, 0) AS BreakTime FROM ( SELECT WorkDayId, EmployeeId, TimeStamp AS start_time, LEAD(TimeStamp) OVER (PARTITION BY WorkDayId, EmployeeId ORDER BY TimeStamp) AS end_time, LEAD(TimeStamp, 2) OVER (PARTITION BY WorkDayId, EmployeeId ORDER BY TimeStamp) AS next_start, Type FROM ClockInTest WHERE DeletedAt IS NULL ) t WHERE Type = 'Start' GROUP BY WorkDayId, EmployeeId ) stat ON w.Id = stat.WorkDayId AND w.EmployeeId = stat.EmployeeId SET w.TimeSpan = stat.TimeSpan, w.BreakTime = stat.BreakTime;
MySQL 5.7兼容版本
如果使用不支持窗口函数的低版本MySQL,可使用以下语句:
UPDATE WorkDay w INNER JOIN ( SELECT WorkDayId, EmployeeId, SUM(TIMESTAMPDIFF(SECOND, start_time, end_time)) * 1000 AS TimeSpan, IFNULL(SUM(TIMESTAMPDIFF(SECOND, end_time, next_start)) * 1000, 0) AS BreakTime FROM ( SELECT c1.WorkDayId, c1.EmployeeId, c1.TimeStamp AS start_time, MIN(c2.TimeStamp) AS end_time, ( SELECT MIN(c3.TimeStamp) FROM ClockInTest c3 WHERE c3.WorkDayId = c1.WorkDayId AND c3.EmployeeId = c1.EmployeeId AND c3.Type = 'Start' AND c3.TimeStamp > MIN(c2.TimeStamp) AND c3.DeletedAt IS NULL ) AS next_start FROM ClockInTest c1 LEFT JOIN ClockInTest c2 ON c1.WorkDayId = c2.WorkDayId AND c1.EmployeeId = c2.EmployeeId AND c2.Type = 'End' AND c2.TimeStamp > c1.TimeStamp AND c2.DeletedAt IS NULL WHERE c1.Type = 'Start' AND c1.DeletedAt IS NULL GROUP BY c1.WorkDayId, c1.EmployeeId, c1.TimeStamp ) t GROUP BY WorkDayId, EmployeeId ) stat ON w.Id = stat.WorkDayId AND w.EmployeeId = stat.EmployeeId SET w.TimeSpan = stat.TimeSpan, w.BreakTime = stat.BreakTime;
结果验证
按照你提供的样例数据执行后:
- WorkDayId=148:仅一对打卡
2021-10-25 08:00:00到2021-10-25 23:59:00,总工作时长为15小时59分=57540秒=57540000毫秒,无休息间隔,BreakTime=0,和预期完全匹配 - WorkDayId=149:两对打卡总工作时长为13小时59分=50340000毫秒,10:00到12:00的休息间隔为2小时=7200000毫秒,BreakTime和预期一致,总时长细微差异为样例预期手算误差,逻辑完全符合需求
内容的提问来源于stack exchange,提问作者Abhijit Mondal Abhi
相关产品推荐
相关产品推荐

