SQL逐整点精确统计在场人数 修正时间匹配逻辑
问题说明
现有人员在场记录表Present,存储字段为人员ID(IdNum)、到场时间(BeginDate)、离场时间(ExitDate),样例数据如下:
IdNum BeginDate Exitdate ------------------------------------------------------------------------- 123 2022-06-13 09:03 2022-06-13 22:12 633 2022-06-13 08:15 2022-06-13 13:09 389 2022-06-13 10:03 2022-06-13 18:12 665 2022-06-13 08:30 2022-06-13 10:16
需求为统计指定时间范围内每个整点精确时刻的在场人员数量,输出字段为整点时间Time、对应在场人数Num_Of_ID_Present,统计规则如下:
- 仅统计整点时刻精确在场的人员,即人员到场时间早于等于整点、离场时间晚于等于整点时才计入统计
- 两个整点之间进出、未覆盖任何整点时刻的人员,不计入统计结果
原有递归CTE实现存在逻辑错误:判断在场时额外加了1小时时间偏移,实际统计的是整点后1小时区间内的在场人数,不符合精确时刻统计要求,原有错误代码如下:
declare @st datetime = '2022-06-13 09:00', @en datetime = '2022-06-13 18:30'; with rcte as ( select [Time] = @st union all select [Time] = dateadd(minute, 60, [Time]) from rcte where [Time] < @en ) select * from rcte r cross apply ( select cnt = count(*) from Present p where p.BeginDate <= dateadd(minute, 60, r.[Time]) and p.ExitDate >= r.[Time] ) c
修正后SQL代码
核心修改点:去掉在场判断条件中多余的1小时偏移,直接判断当前整点时间是否落在人员在场时间区间内,同时调整递归步长为按小时累加、增加递归层级配置避免跨天统计时报错,代码如下:
-- 定义统计起止时间,可根据实际需求修改 declare @st datetime = '2022-06-13 09:00', @en datetime = '2022-06-13 22:00'; with rcte as ( -- 递归起始:第一个统计整点 select [Time] = @st union all -- 递归步长:每次加1小时,生成所有需要统计的整点时间 select [Time] = dateadd(hour, 1, [Time]) from rcte where [Time] < @en ) select r.[Time], c.cnt AS Num_Of_ID_Present from rcte r cross apply ( -- 统计当前整点时刻的在场人数 select cnt = count(IdNum) from Present p where p.BeginDate <= r.[Time] and p.ExitDate >= r.[Time] ) c -- 取消递归层级限制,支持大时间范围统计 option (maxrecursion 0);
结果校验(匹配样例数据)
用提供的样例数据运行上述代码,输出结果与期望完全一致:
- 09:00:在场人员为633、665,共2人
- 10:00:在场人员为123、633、665,共3人
- 11:00~13:00:在场人员为123、633、389,共3人
- 14:00~18:00:在场人员为123、389,共2人
- 19:00~22:00:仅123在场,共1人
内容的提问来源于stack exchange,提问作者KapSht
相关产品推荐
相关产品推荐

