sql-server – 展平/合并重叠的时间间隔

我有一个包含数百万行的“服务”表.每行对应于工作人员在给定日期和时间间隔内提供的服务(每行具有唯一ID).在某些情况下,工作人员可能会在重叠的时间范围内提供服务.我需要编写一个合并重叠时间间隔的查询,并以下面显示的格式返回数据.

我尝试按StaffID和Date字段进行分组,并获得开始时间的最小值和结束时间的最大值,但这并不考虑非重叠的时间范围.我怎么能做到这一点?同样,该表包含数百万条记录,因此递归CTE方法可能会出现性能问题.提前致谢.

服务表

ID    StaffID  Date        BeginTime EndTime
1     101      2014-01-01  08:00     09:00
2     101      2014-01-01  08:30     09:30
3     101      2014-01-01  18:00     20:30
4     101      2014-01-01  19:00     21:00

产量

StaffID Date        BeginTime EndTime
101     2014-01-01  08:00     09:30
101     2014-01-01  18:00     21:00

这是另一个样本数据集,其中包含由贡献者提出的查询.
http://sqlfiddle.com/#!6/bfbdc/3

结果集中的前两行应合并为一行(06:00-08:45),但它会生成两行(06:00-08:30& 06:00-08:45)

最佳答案 我只想出了一个CTE查询,因为问题是可能存在一系列重叠时间,例如:记录1与记录2重叠,记录2与记录3重叠,依此类推.如果没有CTE或其他类型的循环等,这很难解决.无论如何,请试一试.

CTE查询的第一部分获取启动新组的服务,并且与其他服务没有相同的开始时间(我只需要一条启动组的记录).第二部分是那些开始组的人,但是有多个人有相同的开始时间 – 再次,我只需要其中一个.最后一部分递归地建立在起始组上,采用所有重叠的服务.

这是SQLFiddle,添加了更多记录以演示不同类型的重叠和重复时间.

我无法使用ServiceID,因为它必须以与BeginTime相同的方式进行排序.

;with flat as
(
 select StaffID, ServiceDate, BeginTime, EndTime, BeginTime as groupid 
 from services S1
 where not exists (select * from services S2 
 where S1.StaffID = S2.StaffID 
 and S1.ServiceDate = S2.ServiceDate 
 and S2.BeginTime <= S1.BeginTime and S2.EndTime <> S1.EndTime
 and S2.EndTime > S1.BeginTime)

  union all

  select StaffID, ServiceDate, BeginTime, EndTime, BeginTime as groupid 
  from services S1
 where exists (select * from services S2 
 where S1.StaffID = S2.StaffID 
 and S1.ServiceDate = S2.ServiceDate 
 and S2.BeginTime = S1.BeginTime and S2.EndTime > S1.EndTime)
   and not exists (select * from services S2 
 where S1.StaffID = S2.StaffID 
 and S1.ServiceDate = S2.ServiceDate 
 and S2.BeginTime < S1.BeginTime
 and S2.EndTime > S1.BeginTime)

 union all

 select S.StaffID, S.ServiceDate, S.BeginTime, S.EndTime, flat.groupid 
 from flat
 inner join services S 
 on flat.StaffID = S.StaffID
 and flat.ServiceDate = S.ServiceDate
 and flat.EndTime > S.BeginTime
 and flat.BeginTime < S.BeginTime and flat.EndTime < S.EndTime
)

select StaffID, ServiceDate, MIN(BeginTime) as begintime, MAX(EndTime) as endtime 
from flat
group by StaffID, ServiceDate, groupid
order by StaffID, ServiceDate, begintime, endtime
点赞