我尝试仅使用 SQL 从分组时间间隔集中选择常见的重叠时间间隔(或周期,这可能是正确的词)。
现实世界的场景是一个具有 3 个以上可以接听电话的位置的调用中心。职位由特定的服务代表填补,他们的职位分配会随着时间的推移而变化,但这与这个问题无关。我们可以假设对于给定的职位,它总是由某人填补。
职位数量随着时间的推移而缓慢变化。我正在尝试概括该解决方案,以便它可以处理任意数量的位置。
输入数据是一组调用,这些调用定向到某个位置并具有开始时间和结束时间。显然,给定位置不能与其自身有重叠的调用(假设一次只能接听一个调用),但其调用可以在时间上与对其他位置的一个或多个调用重叠。
问题是从调用数据中识别所有位置都在通话的所有时间间隔,因此调用中心无法应答该时间段内的任何新来电(“所有位置都忙”)。
例如,对于三个位置(编号为 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 < b.EndTime 且 a.EndTime >= b.StartTime 时,两个时间间隔 (a, b) 重叠。
如果我可以获得所有位置都有重叠的调用时间间隔集,则关联的“全忙”时间间隔由该集合中最大(最近)的开始时间和最小(最旧)的结束时间组成。
为了更接近解决方案,我正在寻找一种通用算法来确定 n 个时间间隔何时相互重叠。对于区间a、b、c,选择a 重叠b 和a 重叠c 的限制性不够。 A 可以与 b 重叠,但 b 可能不会与 c 重叠,并且您需要所有间隔都彼此重叠。
我正在使用 SQL Server 进行测试。我尝试在网上搜索,但没有找到任何完全涵盖这种情况的内容(关于两个重叠时间间隔的简单情况的大量讨论)。我会分享 SQL,但我仍在尝试找出“方法”,这是需要它来说明的。
即使我只有 SQL-Server 进行测试,我也希望解决方案尽可能通用,因为它可能不会在 SQL Server 上实现。
最佳答案
让我们将其视为随时获取同时调用的数量。该方法是获取时间列表,+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+ 中可用的结构,但在早期版本中不可用(当我写这篇文章时,没有任何版本指示)。
关于sql - 重叠时间间隔 : Select "all busy" periods,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26577322/