You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MySQL补全clockInTest考勤后计算工时更新WorkDay表的实现问题

考勤统计更新SQL实现方案

实现逻辑

  1. 按WorkDayId、EmployeeId分组,将同组内的有效打卡记录按时间戳排序,配对相邻的Start和End打卡
  2. 总工作时长计算:所有配对的Start到对应End的秒级时间差之和乘以1000转毫秒
  3. 休息时长计算:所有配对的End到下一个Start的秒级间隔之和乘以1000转毫秒,无间隔则返回0
  4. 关联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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 00:54:07