以下处理反转日期范围并正确处理与目标范围的开始和/或结束重叠的范围。 编辑:更新以处理未找到适用范围的情况。
declare @DateRanges as Table ( Id Int Identity, SDate Date, EDate Date );
insert into @DateRanges ( SDate, EDate ) values
( '20130105', '20130112' ),
( '20130113', '20130118' ),
( '20130205', '20130312' ),
( '20130708', '20130831' ),
-- Additional test data for ranges that overlap the target date range, or not.
( '20100101', '20130101' ),
( '20131127', '20140102' ),
( '19990208', '20041118' ),
( '20601113', '20990101' );
select * from @DateRanges order by SDate;
declare @StartDate as Date = '20130101';
declare @EndDate as Date = DateAdd( day, -1, DateAdd( year, 1, @StartDate ) );
select @StartDate as [@StartDate], @EndDate as [@EndDate];
with SortedDateRanges as (
-- Sort the date ranges so that we have a dense row number for later use.
select SDate, EDate, Row_Number() over ( order by SDate ) as RN
from @DateRanges
where EDate >= @StartDate and SDate <= @EndDate ),
PairedDateRanges as (
-- Pair the adjacent date ranges and turn them inside out.
select DateAdd( day, 1, L.EDate ) as SDate, DateAdd( day, -1, R.SDate ) as EDate
from SortedDateRanges as L inner join
SortedDateRanges as R on R.RN = L.RN + 1 )
-- The result is all of inside out date ranges that are valid, i.e. don't end before they start...
select SDate, EDate, 'Fill Gap' as Reason
from PairedDateRanges
where SDate <= EDate
union
-- ... plus any leading date range ...
select @StartDate, DateAdd( day, -1, SDate ), 'Leading'
from SortedDateRanges
where RN = 1 and SDate > @StartDate
union
-- ... plus any trailing date range ...
select DateAdd( day, 1, EDate ), @EndDate, 'Trailing'
from SortedDateRanges
where RN = ( select Max( RN ) from SortedDateRanges ) and EDate < @EndDate
union
-- ... or we have nothing.
select @StartDate, @EndDate, 'No Data'
where not exists ( select 42 from SortedDateRanges )
order by SDate;