How to get count of consecutive dates

前端 未结 3 1320
眼角桃花
眼角桃花 2021-01-04 14:35

For example there is some table with dates:

2015-01-01
2015-01-02
2015-01-03
2015-01-06
2015-01-07
2015-01-11

I have to write ms sql query,

相关标签:
3条回答
  • 2021-01-04 14:54
    CREATE TABLE #T ( MyDate DATE) ;
    INSERT #T VALUES ('2015-01-01'),('2015-01-02'),('2015-01-03'),('2015-01-06'),('2015-01-07'),('2015-01-11')
    
    SELECT 
        RW=ROW_NUMBER() OVER( PARTITION BY GRP  ORDER BY MyDate) ,MyDate
    FROM
    (
    SELECT 
        MyDate, DATEDIFF(Day, '1900-01-01' , MyDate)- ROW_NUMBER() OVER( ORDER BY MyDate ) AS GRP
    FROM #T 
    ) A
    
    DROP TABLE #T;
    
    0 讨论(0)
  • 2021-01-04 14:54

    I'm assuming this table:

    SELECT * 
    INTO #Dates
    FROM (VALUES
      (CAST('2015-01-01' AS DATE)),
      (CAST('2015-01-02' AS DATE)),
      (CAST('2015-01-03' AS DATE)),
      (CAST('2015-01-06' AS DATE)),
      (CAST('2015-01-07' AS DATE)),
      (CAST('2015-01-11' AS DATE))) dates(d);
    

    Here's a recursive solution with explanations:

    WITH
      dates AS (
        SELECT
          d, 
          -- This checks if the current row is the start of a new group by using LAG()
          -- to see if the previous date is adjacent
          CASE datediff(day, d, LAG(d, 1) OVER(ORDER BY d)) 
            WHEN -1 THEN 0 
            ELSE 1 END new_group,
          -- This will be used for recursion
          row_number() OVER(ORDER BY d) rn
        FROM #Dates
      ),
      -- Here, the recursion happens
      groups AS (
        -- We initiate recursion with rows that start new groups, and calculate "GRP"
        -- numbers
        SELECT d, new_group, rn, row_number() OVER(ORDER BY d) grp
        FROM dates
        WHERE new_group = 1
        UNION ALL
        -- We then recurse by the previously calculated "RN" until we hit the next group
        SELECT dates.d, dates.new_group, dates.rn, groups.grp
        FROM dates JOIN groups ON dates.rn = groups.rn + 1
        WHERE dates.new_group != 1
      )
    -- Finally, we enumerate rows within each group
    SELECT d, row_number() OVER (PARTITION BY grp ORDER BY d)
    FROM groups
    ORDER BY d
    

    SQLFiddle

    0 讨论(0)
  • 2021-01-04 15:00

    You can use this CTE:

    ;WITH CTE AS (
       SELECT [Date],        
              ROW_NUMBER() OVER(ORDER BY [Date]) AS rn,
              CASE WHEN DATEDIFF(Day, PrevDate, [Date]) IS NULL THEN 0
                   WHEN DATEDIFF(Day, PrevDate, [Date]) > 1 THEN 0
                   ELSE 1
              END AS flag
       FROM (
          SELECT [Date], LAG([Date]) OVER (ORDER BY [Date]) AS PrevDate
          FROM #Dates ) d
    )
    

    to produce the following result:

    Date        rn  flag
    ===================
    2015-01-01  1   0
    2015-01-02  2   1
    2015-01-03  3   1
    2015-01-06  4   0
    2015-01-07  5   1
    2015-01-11  6   0
    

    All you have to do now is to calculate a running total of flag up to the first occurrence of a preceding zero value:

    ;WITH CTE AS (
       ... cte statements here ...
    )
    SELECT [Date], b.cnt + 1
    FROM CTE AS c
    OUTER APPLY (
       SELECT TOP 1 COALESCE(rn, 1) AS rn 
       FROM CTE
       WHERE flag = 0 AND rn < c.rn
       ORDER BY rn DESC
    ) a 
    CROSS APPLY (
       SELECT COUNT(*) AS cnt
       FROM CTE 
       WHERE c.flag <> 0 AND rn < c.rn AND rn >= a.rn
    ) b
    

    OUTER APPLY calculates the rn value of the first zero-valued flag that comes before the current row. CROSS APPLY calculates the number of records preceding the current record up to the first occurrence of a preceding zero valued flag.

    0 讨论(0)
提交回复
热议问题