0

我有第一张表定义了工作时间:FreeTimes table (start datetime, end datetime)第二张表已经计划了任务:TaskTime table (start datetime, end datetime)

我需要以某种方式从第一个表中减去第二个表,所以在这种情况下我得到了一个剩余空闲时间的结果集:

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

1 回答 1

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)

Where we basically order all datetime values of interest, and then for each pair of successive values, work out if there's some overlap with the TaskTimes table. If there is, then that pair shouldn't be in the final result. (edit - we also have to check that the interval pair does actually overlap with FreeTimes too)

You can, if needed, take this further and merge intervals (if there are overlapping rows in FreeTimes, you may end up with multiple intervals which are adjacent to each other)

于 2012-10-30T08:44:11.917 回答