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

如何编写SQL按时间区间统计同时在岗的员工总人数

解决方案

你要的在岗人数分时段统计可以通过事件拆分累计法实现,这是处理此类时间区间重叠统计的通用方案,适配SQL Server环境(你的原查询语法为SQL Server风格),完整实现代码如下:

WITH base_data AS (
    -- 基础数据:取出原始时间字段,处理跨天的离岗时间
    SELECT 
        linka.xLinka AS Line,
        linka.xDoklad AS Document,
        zam.xPracovnik AS Employee,
        -- 转成datetime类型方便计算,可根据实际字段类型调整转换逻辑
        CAST(zam.xCasOd AS DATETIME) AS arrival_time,
        CASE 
            WHEN CAST(zam.xCasDo AS DATETIME) < CAST(zam.xCasOd AS DATETIME) 
            THEN DATEADD(DAY, 1, CAST(zam.xCasDo AS DATETIME))
            ELSE CAST(zam.xCasDo AS DATETIME) 
        END AS departure_time
    FROM [K2CA_CA].[dbo].[_OV_Data01] as linka
    LEFT OUTER JOIN dbo._OV_Data03 as zam ON zam.xLinka = linka.xLinka and zam.xDoklad = linka.xDoklad
    WHERE linka.xRok = 2021
        --AND linka.xDen  >= '2021-10-20' and linka.xDen <= '2021-10-26'
        AND (zam.xPozice like '%Bale%' or zam.xPozice like '%Plnič%')
),
time_events AS (
    -- 拆分事件:到岗记+1,离岗记-1
    SELECT Line, Document, arrival_time AS event_time, 1 AS delta FROM base_data
    UNION ALL
    SELECT Line, Document, departure_time AS event_time, -1 AS delta FROM base_data
),
sorted_events AS (
    -- 计算累计在岗人数
    SELECT 
        Line,
        Document,
        event_time,
        SUM(delta) OVER (PARTITION BY Line, Document ORDER BY event_time) AS running_total
    FROM time_events
),
intervals AS (
    -- 拼接相邻时间点为统计区间
    SELECT 
        Line,
        Document,
        event_time AS interval_start,
        LEAD(event_time) OVER (PARTITION BY Line, Document ORDER BY event_time) AS interval_end,
        running_total AS on_duty_count
    FROM sorted_events
)
-- 输出最终结果,格式化时间和说明
SELECT 
    Line,
    Document,
    on_duty_count AS [COUNT(*)],
    CONCAT(
        FORMAT(interval_start, 'HH:mm'), 
        ' ', 
        FORMAT(interval_end, 'HH:mm'),
        ' (',
        FORMAT(interval_start, 'HH:mm'),
        ' - ',
        FORMAT(interval_end, 'HH:mm'),
        ' 共有 ',
        on_duty_count,
        ' 名员工在岗)'
    ) AS [Arrival   Departure]
FROM intervals
WHERE on_duty_count > 0 -- 过滤掉无人在岗的区间
ORDER BY Line, Document, interval_start

逻辑说明

  • 第一步先处理原始时间字段,自动识别跨天的离岗时间(比如当日22点到次日6点的班次),避免时间计算错误
  • 把每个员工的到岗、离岗拆成两个独立事件,到岗时在岗人数+1,离岗时-1
  • 按时间排序所有事件,计算每个时间点的累计在岗人数
  • 把相邻两个事件的时间点拼成统计区间,相同区间内的在岗人数完全一致
  • 最后过滤掉无人在岗的区间,格式化输出即可

内容的提问来源于stack exchange,提问作者Radek Tarant

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 10:24:02