我解决这个问题的一般方法如下:
;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)