1

반환되는 날짜 범위를 "음수"날짜 범위의 형식으로 변환하는 인라인 (즉, UDF os SPROC) 선택의 일부 작업을하고 있습니다. . (단지 우리가 2013 년에 관심이 있다고 가정) 이 날짜 기간 "반복"작업에서 재귀 쿼리가 도움이 될 수 있습니까?

01/01/2013 01/04/2013 
01/19/2013 02/04/2013 
03/13/2013 07/07/2013 
09/01/2013 12/31/2013 

오른쪽에 I 오전

1 01/05/2013 01/12/2013 
2 01/13/2013 01/18/2013 
3 02/05/2013 03/12/2013 
4 07/08/2013 08/31/2013 

구함 결과 :

SELECT id, SDate, EDate 
FROM table 
ORDER BY SDate 

샘플 세트 : 여기에 "소스"설정되어 CTE를 사용하여 재귀 쿼리를 만들려고 시도하는 것을 추적합니까? 누구나 공유 할 수있는 SQL이 있습니까?

+0

내 짧은 대답에는 무엇이 누락 되었습니까? –

답변

1

다음은 날짜 범위를 반전하고 대상 범위의 시작 및/또는 끝과 겹치는 범위를 올바르게 처리합니다. EDIT : 해당 범위가없는 경우를 처리하도록 업데이트되었습니다.

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; 
+0

내가 가고있는 곳과 매우 흡사하다. 저에게 시간을 절약 해 주셔서 감사합니다 !! –

+0

원본 세트가 비어있을 때 가장자리 케이스를 포함하도록 답변을 완성 할 수 있습니까? 나는 이것이 다음과 같다고 생각한다 : ---- 어떤 주요한 날짜 범위 ... \t SELECT @PeriodSDate, CASE WHEN cal.RN IS NULL THP @Periodedate ELSE DateAdd (day, -1, cal.start_date) END, '선행'보낸 \t를 AS DEF \t \t LEFT 외부 (SortedDateRanges SELECT *) SortedDateRanges 존재 ON 살았어 가입 (시작일, 종료일 @PeriodEDate만큼 @PeriodSDate SELECT) \t \t \t WHERE (RN = 1 AND cal.start_date > @PeriodSDate) \t \t 또는 \t \t (cal.RN IS NULL) ' –

+0

@ G.Stoynev - 답변이 올라 왔습니다. 빈 입력 테이블 또는 대상 범위의 날짜 범위가없는 테이블을 처리하기 위해 ated. 아무데도 선택하지 않는 다른 UNION을 추가하는 것이 가장 쉬운 것 같았다. – HABO

2
declare @t table (SDate date, Edate date) 
insert @t values ('2013-01-01', '2013-12-20') 

declare @year int = 2013 

;with dates as 
(
select dateadd(year, @year - 1900, 0) d 
union all 
select d + 1 
from dates where 
d < dateadd(year, @year - 1899, -1) 
), 
b as 
(
select d, grp = d-row_number() over (order by d) from dates 
where not exists (select 1 from @t where dates.d between SDate and EDate) 
) 
select min(d), max(d) from b group by grp 
option (maxrecursion 366)