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

跨天班次员工打卡间隔计算与打卡状态判定SQL查询问题

兼容跨天/单日班次的打卡统计SQL解决方案

核心问题根因

原有查询使用trunc(Timeinout)(打卡自然日)作为LEAD/LAG的分区字段,仅能归集当日打卡的单日班次数据,跨天班次中次日凌晨的打卡会被划分到下一个自然日分区,导致同归属考勤日的打卡被拆分,间隔计算和状态判定全部错误。

修正思路

利用表中已有的flag字段计算归属考勤日作为分区依据:

  • flag=0:打卡归属当天,归属考勤日 = 打卡自然日
  • flag=1:打卡归属前一天,归属考勤日 = 打卡自然日 - 1天
    统一计算逻辑为:TRUNC(Timeinout) - flag

修正后完整SQL

SELECT X.*,
       CASE
         WHEN Previous_Movment IS NULL AND Next_Movment IS NOT NULL THEN
          '首卡'
         WHEN Previous_Movment IS NOT NULL AND Next_Movment IS NULL THEN
          '末卡'
         WHEN Previous_Movment IS NULL AND Next_Movment IS NULL THEN
          '当日无打卡'
         ELSE
          '日间打卡'
       END CHECK_STATUS
  FROM (SELECT 
               -- 替换为归属考勤日,不再使用打卡自然日
               TRUNC(a.timeinout) - a.flag AS attendance_date,
               a.timeinout current_movment,
               -- 分区字段替换为归属考勤日
               LEAD(TIMEINOUT) OVER(PARTITION BY TRUNC(a.timeinout) - a.flag, Emp_ID ORDER BY TIMEINOUT) Next_Movment,
               LAG(TIMEINOUT) OVER(PARTITION BY TRUNC(a.timeinout) - a.flag, Emp_ID ORDER BY TIMEINOUT) Previous_Movment,
               -- 时间间隔计算逻辑保持不变,仅调整分区字段
               TRUNC(24 *
                     MOD(LEAD(TIMEINOUT) OVER(PARTITION BY TRUNC(a.timeinout) - a.flag,
                              Emp_ID ORDER BY TIMEINOUT) - TIMEINOUT,
                         1)) AS diff_hours,
               TRUNC(MOD(MOD(LEAD(TIMEINOUT)
                             OVER(PARTITION BY TRUNC(a.timeinout) - a.flag,
                                  Emp_ID ORDER BY TIMEINOUT) - TIMEINOUT,
                             1) * 24,
                         1) * 60) AS diff_minus,
               TRUNC(MOD(MOD(MOD(LEAD(TIMEINOUT)
                                 OVER(PARTITION BY TRUNC(a.timeinout) - a.flag,
                                      Emp_ID ORDER BY TIMEINOUT) - TIMEINOUT,
                                 1) * 24,
                             1) * 60,
                         1) * 60) AS diff_sec,
               Emp_ID,
               FLAG Return_Previous_day_or_not
          FROM My_table a
         WHERE TRUNC(a.timeinout) BETWEEN
               TO_DATE('03-07-2018', 'dd-mm-yyyy') AND
               TO_DATE('07-07-2018', 'dd-mm-yyyy')
          -- 可根据需要放开/调整员工过滤条件
          -- AND a.Emp_ID = 2
        ) X
ORDER BY X.EMP_ID, X.attendance_date, X.current_movment

效果验证

以测试数据中员工1的2018-07-03考勤日为例:

  • 会同时归集7月3日16:39(flag=0)、7月4日01:14:40(flag=1)、7月4日01:14:44(flag=1)三条同归属日的打卡记录
  • 相邻间隔计算正常,首卡为7月3日16:39的记录,末卡为7月4日01:14:44的记录,完全符合跨天班次的考勤规则
  • 单日班次的员工2的计算逻辑与原有正确结果完全一致,无需额外调整

内容的提问来源于stack exchange,提问作者M.Youssef

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 19:45:01