在T-SQL中减去DateTime间隔

时间:2012-10-30 08:34:05

标签: tsql

我有第一个表格,其中包含已定义的工作时间:FreeTimes table (start datetime, end datetime)和第二个已计划任务的表格:TaskTime table (start datetime, end datetime)

我需要以某种方式从第一个表中减去第二个表,所以我在这种条件下得到了一个自由时间的结果集:

  • 如果TaskTime(或更多TaskTimes)位于FreeTime中间,我需要将FreeTime拆分为任务之后的时间和任务之后的时间
  • 如果TaskTime与整个FreeTime重叠,我需要过滤掉这个FreeTime
  • 如果TaskTime与FreeTime相交,我需要从FreeTime中减去TaskTime并只留下FreeTime的部分内容

1 个答案:

答案 0 :(得分:2)

我解决这个问题的一般方法如下:

;With AllTimes as (
    select [Start] as EventTime from FreeTimes
    union
    select [End] from FreeTimes
    union
    select [Start] from TaskTimes
    union
    select [End] from TaskTimes
), OrderedTimes as (
    select EventTime,ROW_NUMBER() OVER (ORDER BY EventTime) rn
    from AllTimes
), Intervals as (
    select
        ot1.EventTime as StartTime,
        ot2.EventTime as EndTime
    from
        OrderedTimes ot1
            inner join
        OrderedTimes ot2
            on
                ot1.rn = ot2.rn - 1
)
select * from Intervals i
where not exists (
    select * from TaskTimes T where --Overlapped
       T.[Start] < i.EndTime and
       T.[End] > i.StartTime)
and exists (
    select * from FreeTimes T where
       T.[Start] < i.EndTime and
       T.[End] > i.StartTime)

我们基本上对所有感兴趣的日期时间值进行排序,然后对于每对连续值,如果与TaskTimes表有一些重叠,则计算出来。如果有,则该对不应该在最终结果中。 (编辑 - 我们还必须检查区间对是否确实与FreeTimes重叠)

如果需要,您可以更进一步并合并间隔(如果FreeTimes中有重叠的行,您可能最终会有多个彼此相邻的间隔)