복붙노트

[SQL] 연속 날짜를 감지하는 것은 SQL을 사용하여 범위

SQL

연속 날짜를 감지하는 것은 SQL을 사용하여 범위

나는 시작과 끝 날짜 정보를 필요로 달력 개체를 채우려. 나는 날짜의 순서를 포함하는 하나의 열을 가지고있다. 날짜 중 일부는 연속입니다 (하루 차이가) 일부는 아니다.

InfoDate  

2013-12-04  consecutive date [StartDate]
2013-12-05  consecutive date
2013-12-06  consecutive date [EndDate]

2013-12-09                   [startDate]
2013-12-10                   [EndDate]

2014-01-01                   [startDate]
2014-01-02 
2014-01-03                   [EndDate]

2014-01-06                   [startDate]
2014-01-07                   [EndDate]

2014-01-29                   [startDate]
2014-01-30 
2014-01-31                   [EndDate]

2014-02-03                   [startDate]
2014-02-04                   [EndDate]

나는 각각의 연속 날짜의 시작 및 종료 날짜 (첫 번째와 블록의 마지막 한) 범위를 선택하고 싶다.

StartDate     EndDate

2013-12-04    2013-12-06
2013-12-09    2013-12-10
2014-01-01    2014-01-03
2014-01-06    2014-01-07
2014-01-29    2014-01-31
2014-02-03    2014-02-04

난 단지 SQL을 사용하여 문제를 해결합니다.

해결법

  1. ==============================

    1.아니 조인 또는 재귀 CTE는 필요. 즉 연속하는 시퀀스 내의 불변이기 때문에 표준 틈새 및 섬 용액 (마이너스 값 ROW_NUMBER)가 그룹이다. 시작 및 종료 날짜는 그룹의 MIN () 및 MAX ()입니다.

    아니 조인 또는 재귀 CTE는 필요. 즉 연속하는 시퀀스 내의 불변이기 때문에 표준 틈새 및 섬 용액 (마이너스 값 ROW_NUMBER)가 그룹이다. 시작 및 종료 날짜는 그룹의 MIN () 및 MAX ()입니다.

    WITH t AS (
      SELECT InfoDate d,ROW_NUMBER() OVER(ORDER BY InfoDate) i
      FROM @d
      GROUP BY InfoDate
    )
    SELECT MIN(d),MAX(d)
    FROM t
    GROUP BY DATEDIFF(day,i,d)
    
  2. ==============================

    2.여기 요 ..

    여기 요 ..

    ;WITH CTEDATES
    AS
    (
        SELECT ROW_NUMBER() OVER (ORDER BY Infodate asc ) AS ROWNUMBER,infodate FROM YourTableName  
    
    ),
     CTEDATES1
    AS
    (
       SELECT ROWNUMBER, infodate, 1 as groupid FROM CTEDATES WHERE ROWNUMBER=1
       UNION ALL
       SELECT a.ROWNUMBER, a.infodate,case datediff(d, b.infodate,a.infodate) when 1 then b.groupid else b.groupid+1 end as gap FROM CTEDATES A INNER JOIN CTEDATES1 B ON A.ROWNUMBER-1 = B.ROWNUMBER
    )
    
    select min(mydate) as startdate, max(infodate) as enddate from CTEDATES1 group by groupid
    

    이 질문에 대답하는 경우, 대답으로 표시하는 것을 잊지 마십시오.

  3. ==============================

    3.나는 #consec 전화 후 다음을 perforemed 테이블에 이러한 값을 삽입했습니다 :

    나는 #consec 전화 후 다음을 perforemed 테이블에 이러한 값을 삽입했습니다 :

    select t1.*
    ,t2.infodate as binfod
    into #temp1
    from #consec t1
    left join #consec t2 on dateadd(DAY,1,t1.infodate)=t2.infodate
    
    select t1.*
    ,t2.infodate as binfod
    into #temp2
    from #consec t1
    left join #consec t2 on dateadd(DAY,1,t2.infodate)=t1.infodate
    ;with cte as(
    select infodate,  ROW_NUMBER() over(order by infodate asc) as seq from #temp1
    where binfod is null
    ),
    cte2 as(
    select infodate, ROW_NUMBER() over(order by infodate asc) as seq from #temp2
    where binfod is null
    )
    
    select t2.infodate as [start_date]
    ,t1.infodate as [end_date] from cte t1
    left join cte2 t2 on t1.seq=t2.seq 
    

    언제 까지나 당신의 날짜 기간이 중복되지 않기 때문에, 그것은 당신을 위해 일을해야한다.

  4. ==============================

    4.여기에는 테스트 데이터 내 샘플입니다 :

    여기에는 테스트 데이터 내 샘플입니다 :

    --required output
    -- 01 - 03
    -- 08 - 09
    -- 12 - 14
    
    DECLARE @maxRN int;
    WITH #tmp AS (
                    SELECT CAST('2013-01-01' AS date) DT
        UNION ALL   SELECT CAST('2013-01-02' AS date)
        UNION ALL   SELECT CAST('2013-01-03' AS date)
        UNION ALL   SELECT CAST('2013-01-05' AS date)
        UNION ALL   SELECT CAST('2013-01-08' AS date)
        UNION ALL   SELECT CAST('2013-01-09' AS date)
        UNION ALL   SELECT CAST('2013-01-12' AS date)
        UNION ALL   SELECT CAST('2013-01-13' AS date)
        UNION ALL   SELECT CAST('2013-01-14' AS date)
    ),
    #numbered AS (
        SELECT 0 RN, CAST('1900-01-01' AS date) DT
        UNION ALL
        SELECT ROW_NUMBER() OVER (ORDER BY DT) RN, DT
        FROM #tmp
    )
    
    SELECT * INTO #tmpTable FROM #numbered;
    SELECT @maxRN = MAX(RN) FROM #tmpTable;
    
    INSERT INTO #tmpTable
    SELECT @maxRN + 1, CAST('2100-01-01' AS date);
    
    WITH #paired AS (
        SELECT 
        ROW_NUMBER() OVER(ORDER BY TStart.DT) RN, TStart.DT DTS, TEnd.DT DTE
        FROM #tmpTable TStart
        INNER JOIN #tmpTable TEnd 
        ON TStart.RN = TEnd.RN - 1
        AND DATEDIFF(dd,TStart.DT,TEnd.DT) > 1  
    )
    
    SELECT TS.DTE, TE.DTs 
    FROM #paired TS
    INNER JOIN #paired TE ON TS.RN = TE.RN -1
    AND TS.DTE <> TE.DTs -- you could remove this filter if you want to have start and end on the same date
    
    DROP TABLE #tmpTable
    

    실제 테이블과 #tmp 데이터를 교체합니다.

  5. ==============================

    5.이 좋아해요 여기에 sqlfiddle입니다 수 있습니다

    이 좋아해요 여기에 sqlfiddle입니다 수 있습니다

    select
      min(ndate) as start_date,
      max(ndate) as end_date
    from
    (select
      ndate,
      dateadd(day, -row_number() over (order by ndate), ndate) as rnk
     from dates
     ) t
     group by
       rnk
    
  6. ==============================

    6.

    SELECT InfoDate ,
        CASE
          WHEN TRUNC(InfoDate - 1) = TRUNC(lag(InfoDate,1,InfoDate) over (order by InfoDate))
          THEN NULL
          ELSE InfoDate
        END STARTDATE,
        CASE
          WHEN TRUNC(InfoDate + 1) = TRUNC(lead(InfoDate,1,InfoDate) over (order by InfoDate))
          THEN NULL
          ELSE InfoDate
        END ENDDATE
      FROM TABLE;
    
  7. from https://stackoverflow.com/questions/20402089/detect-consecutive-dates-ranges-using-sql by cc-by-sa and MIT license