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

如何计算员工每日办公总时长并动态展示多组TimeIn/TimeOut记录?

解决方案:动态生成打卡时段列并计算当日累计时长

没问题,这个需求完全可以实现!由于不同员工每日的进出打卡次数不固定,静态SQL没法适配可变数量的TimeIn/TimeOut字段,我们得用动态SQL来动态生成对应数量的时段列,同时算出当日累计办公时长。

步骤1:先搞定每日累计时长(基础查询)

如果只是需要员工每日的总办公时长,我们可以先按员工ID和日期分组,用秒数计算总时长再转成易读的时分秒格式:

SELECT 
    ID,
    CONVERT(VARCHAR(10), TimeIn, 23) AS Day,
    CONVERT(VARCHAR, DATEADD(SECOND, SUM(DATEDIFF(SECOND, TimeIn, TimeOut)), 0), 108) AS TimeSpent
FROM Attendance
GROUP BY ID, CONVERT(VARCHAR(10), TimeIn, 23)
ORDER BY Day, ID;

这个查询会得到每个员工每日的总时长,结果如下:

ID  Day         TimeSpent
1   2018-01-18  08:37:00
2   2018-01-18  08:08:00
1   2018-01-19  03:28:00
2   2018-01-19  04:26:00

步骤2:动态生成多组TimeIn/TimeOut列

要动态展示每个员工当日的所有进出时段,我们需要先给每个员工的每日打卡记录标记序号,再通过动态SQL生成对应数量的TimeIn和TimeOut列:

第一步:给每日打卡记录加序号

WITH RankedAttendance AS (
    SELECT 
        ID,
        TimeIn,
        TimeOut,
        CONVERT(VARCHAR(10), TimeIn, 23) AS Day,
        ROW_NUMBER() OVER (PARTITION BY ID, CONVERT(VARCHAR(10), TimeIn, 23) ORDER BY TimeIn) AS RowNum
    FROM Attendance
)
SELECT * FROM RankedAttendance;

这个CTE会给每个员工每日的打卡记录按时间顺序编号,比如ID1在2018-01-18的3次打卡会被标记为RowNum=1、2、3。

第二步:编写动态SQL生成可变列

DECLARE @cols NVARCHAR(MAX);
DECLARE @sql NVARCHAR(MAX);

-- 生成动态列名:TimeIn1, TimeOut1, TimeIn2, TimeOut2...
SELECT @cols = STRING_AGG(
    CONCAT('MAX(CASE WHEN RowNum = ', RowNum, ' THEN TimeIn END) AS TimeIn', RowNum, ',',
           'MAX(CASE WHEN RowNum = ', RowNum, ' THEN TimeOut END) AS TimeOut', RowNum),
    ','
)
FROM (
    SELECT DISTINCT RowNum
    FROM (
        SELECT ROW_NUMBER() OVER (PARTITION BY ID, CONVERT(VARCHAR(10), TimeIn, 23) ORDER BY TimeIn) AS RowNum
        FROM Attendance
    ) t
) t;

-- 拼接完整的动态SQL
SET @sql = CONCAT(
'WITH RankedAttendance AS (
    SELECT 
        ID,
        TimeIn,
        TimeOut,
        CONVERT(VARCHAR(10), TimeIn, 23) AS Day,
        ROW_NUMBER() OVER (PARTITION BY ID, CONVERT(VARCHAR(10), TimeIn, 23) ORDER BY TimeIn) AS RowNum
    FROM Attendance
)
SELECT 
    ID,
    ', @cols, ',
    CONVERT(VARCHAR, DATEADD(SECOND, SUM(DATEDIFF(SECOND, TimeIn, TimeOut)), 0), 108) AS TimeSpent,
    Day
FROM RankedAttendance
GROUP BY ID, Day
ORDER BY Day, ID;'
);

-- 执行动态SQL
EXEC sp_executesql @sql;

执行结果说明

运行这段动态SQL后,会根据所有员工的最大每日打卡次数生成对应数量的TimeIn/TimeOut列。针对你的数据,会生成TimeIn1, TimeOut1, TimeIn2, TimeOut2, TimeIn3, TimeOut3三对列,结果如下:

IDTimeIn1TimeOut1TimeIn2TimeOut2TimeIn3TimeOut3TimeSpentDay
12018-01-18 09:37:25.0002018-01-18 11:12:25.0002018-01-18 11:21:25.0002018-01-18 16:32:25.0002018-01-18 16:37:25.0002018-01-18 17:55:25.00008:37:002018-01-18
22018-01-18 09:56:25.0002018-01-18 14:37:25.0002018-01-18 15:00:25.0002018-01-18 18:27:25.000NULLNULL08:08:002018-01-18
12018-01-19 09:12:25.0002018-01-19 11:41:25.0002018-01-19 13:23:25.0002018-01-19 13:31:25.0002018-01-19 17:31:25.0002018-01-19 18:51:25.00003:28:002018-01-19
22018-01-19 12:55:25.0002018-01-19 13:12:25.0002018-01-19 14:01:25.0002018-01-19 18:10:25.000NULLNULL04:26:002018-01-19

这样就完美实现了你的需求:动态展示所有打卡时段,同时计算当日累计时长。

内容的提问来源于stack exchange,提问作者Doonie Darkoo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:35:21