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

如何用SQL按日期统计每位员工的总工时(小时+分钟)?

按日期统计员工每日打卡总时长的SQL实现方法

假设你的打卡数据表名为attendance,包含字段:employee_id(员工ID)、datetime(打卡时间)、type(打卡类型,0=上班,1=下班),以下是针对不同SQL环境的实现方案:

核心思路

先匹配每位员工单日的上下班记录对,计算单次打卡的时长,再按员工+日期维度汇总总时长,最终拆分出小时和分钟数。


通用SQL实现(兼容多数数据库)

利用窗口函数LEAD()关联同员工同日期的下一条打卡记录(上班对应下班):

WITH attendance_pairs AS (
    SELECT
        employee_id,
        DATE(datetime) AS work_date,
        datetime AS in_time,
        -- 获取同员工同日期的下一条打卡记录(即下班时间)
        LEAD(datetime) OVER (PARTITION BY employee_id, DATE(datetime) ORDER BY datetime) AS out_time,
        type
    FROM attendance
)
SELECT
    employee_id,
    work_date,
    -- 计算总小时数:总分钟数整除60
    FLOOR(SUM(TIMESTAMPDIFF(MINUTE, in_time, out_time)) / 60) AS total_hours,
    -- 计算剩余分钟数:总分钟数取余60
    SUM(TIMESTAMPDIFF(MINUTE, in_time, out_time)) % 60 AS total_minutes
FROM attendance_pairs
-- 仅筛选上班记录,且确保有对应的下班记录
WHERE type = 0 AND out_time IS NOT NULL
GROUP BY employee_id, work_date
ORDER BY employee_id, work_date;

分数据库适配版本

1. MySQL 专属实现

如果不使用窗口函数,可通过子查询匹配对应下班记录:

SELECT
    employee_id,
    DATE(datetime) AS work_date,
    FLOOR(SUM(TIMESTAMPDIFF(MINUTE, in_time, out_time)) / 60) AS total_hours,
    SUM(TIMESTAMPDIFF(MINUTE, in_time, out_time)) % 60 AS total_minutes
FROM (
    SELECT
        a1.employee_id,
        a1.datetime AS in_time,
        -- 匹配同员工同日期、晚于上班时间的最早下班记录
        (SELECT MIN(a2.datetime) 
         FROM attendance a2 
         WHERE a2.employee_id = a1.employee_id 
           AND DATE(a2.datetime) = DATE(a1.datetime) 
           AND a2.type = 1 
           AND a2.datetime > a1.datetime) AS out_time
    FROM attendance a1
    WHERE a1.type = 0
) AS paired_records
WHERE out_time IS NOT NULL
GROUP BY employee_id, work_date;

2. SQL Server 专属实现

替换日期函数和时长计算函数:

WITH attendance_pairs AS (
    SELECT
        employee_id,
        CAST(datetime AS DATE) AS work_date,
        datetime AS in_time,
        LEAD(datetime) OVER (PARTITION BY employee_id, CAST(datetime AS DATE) ORDER BY datetime) AS out_time
    FROM attendance
    WHERE type = 0
)
SELECT
    employee_id,
    work_date,
    FLOOR(SUM(DATEDIFF(MINUTE, in_time, out_time)) / 60) AS total_hours,
    SUM(DATEDIFF(MINUTE, in_time, out_time)) % 60 AS total_minutes
FROM attendance_pairs
WHERE out_time IS NOT NULL
GROUP BY employee_id, work_date
ORDER BY employee_id, work_date;

注意事项

  • 若存在员工单日多次上下班(如外出办事再返回),上述逻辑会自动累加所有时段的时长
  • 对于缺失下班记录的情况,可根据业务需求调整(如忽略该条上班记录,或按固定时长统计)
  • 日期处理函数需根据数据库调整:Oracle用TRUNC(datetime),PostgreSQL用DATE(datetime)

内容的提问来源于stack exchange,提问作者Feroz Khan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 17:36:07