重叠时间间隔:选择"所有忙碌"期

时间:2014-10-26 20:04:06

标签: sql sql-server intervals gaps-and-islands sql-server-2014

我试图仅使用SQL从分组时间间隔(或句点)中选择常见的重叠时间间隔,这可能是正确的单词。

现实世界的情景是一个可以接听电话的3个以上位置的呼叫中心。职位由特定服务代表填补,他们对职位的分配随着时间的推移而变化,但这与此问题无关。我们可以假设,对于给定的位置,它总是被某人填充。

职位数量随时间缓慢变化。我试图概括解决方案,以便它可以处理任意数量的位置。

输入数据是一组调用,它们被定向到一个位置并具有开始时间和结束时间。显然,给定的位置不能与自身重叠调用(假设一次只能调用一次),但其调用可以在一次或多次调用其他位置时与时间重叠。

问题是从呼叫数据中识别所有位置在通话中的所有时间间隔,因此呼叫中心无法应答该时段内的任何新来电("所有位置忙碌& #34)

,例如,三个职位(编号为1,2 3)

Call  Position  CallStartTime      CallEndTime

1     1         2014-01-01 14:01   2014-01-01 14:33     <--Comprises all busy intervals 1 and 2
2     1         2014-01-01 14:45   2014-01-01 14:47  
3     1         2014-01-01 14:53   2014-01-01 14:57  
4     2         2014-01-01 13:01   2014-01-01 13:53    
5     2         2014-01-01 13:55   2014-01-01 14:25     <--comprises all busy interval 1
6     2         2014-01-01 14:27   2014-01-01 14:29     <--comprises all busy interval 2
7     2         2014-01-01 14:35   2014-01-01 14:41  
8     3         2014-01-01 14:21   2014-01-01 15:03     <--comprises all busy intervals 1 and 2
9     3         2014-01-01 16:01   2014-01-01 16:11

对于上面的测试数据,当所有位置都忙时(所有位置重叠呼叫的不同情况)有两个时间间隔:14:21-14:25和14:27-14:29。

所以期望的结果集是

AllBusyStartTime  AllBusyEndTime
2014-01-01 14:21  2014-01-01 14:25
2014-01-01 14:27  2014-01-01 14:29 

您看到一个呼叫可能与其他呼叫有多个重叠(例如,呼叫位置1 14:01-14:33与呼叫位置2 13:55-14:25和呼叫位置2 14:27-14重叠:29)。

当a.StartTime&lt;时间间隔时,两个时间间隔(a,b)重叠。 b.EndTime和a.EndTime&gt; = b.StartTime。

如果我能得到一组呼叫时间间隔,其中所有位置都有重叠,则相关的&#34;全部忙碌&#34;时间间隔包括来自集合的GREATEST(最近的)StartTime和最低(最旧的)EndTime。

为了更接近解决方案,我正在寻找一种通用算法来确定n个时间间隔何时相互重叠。对于间隔a,b,c选择重叠b和重叠c不是足够的限制。 A可能重叠b但b可能不会重叠c,您需要所有的间隔相互重叠。

我正在使用SQL Server进行测试。我试过在网上搜索但没有发现任何涵盖这种情况的内容(很多关于两个重叠时间间隔的简单情况的讨论)。我会分享SQL,但我仍然试图弄清楚&#34;方法&#34;,这是需要照亮的。

尽管我的测试只有SQL-Server,但我希望尽可能保持解决方案的通用性,因为它可能不会在SQL Server上实现。

1 个答案:

答案 0 :(得分:2)

让我们随时了解同时获取同时呼叫的数量。方法是获得一个时间列表,其中+1表示呼叫开始,-1表示呼叫结束。以下给出了每个时间段的计数:

select thetime, sum(incall) over (order by thetime, call) as simultaneouscalls
from ((select CallStartTime as thetime, call, +1 as incall
       from calls
      ) union all
      (select CallEndTime, call, -1 as incall
       from calls
      )
     ) c;

接下来,您需要句点,因此请使用lead()来结束句点,然后按同时调用的次数排序:

with c as (
      select thetime, sum(incall) over (order by thetime, call) as simultaneouscalls
      from ((select CallStartTime as thetime, call, +1 as incall
             from calls
            ) union all
            (select CallEndTime, call, -1 as incall
             from calls
            )
           ) c
    )
select thetime, endtime, simultaneouscalls
from (select c.*, lead(thetime) over (order the thetime) as endtime
      from c
     ) c
order by simultaneouscalls, thetime;

如果您确实只想要最大值,请将此where子句添加到外部查询:

where simultaneouscalls = (select count(distinct position) from calls)

注意:这使用了SQL Server 2012+中可用的构造,但在早期版本中没有(因为我写的是没有版本的指示)。