Split date range into one row per month in sql server

前端 未结 2 498
情书的邮戳
情书的邮戳 2020-12-06 02:47

I have a table with two column called \"from_date\" and \"to_date\"

    the table look like:-

相关标签:
2条回答
  • 2020-12-06 03:26

    This is leap year safe and handles date ranges the other answers currently don't.

    DECLARE @d TABLE(from_date DATE, to_date DATE);
    
    INSERT @d VALUES ('2013-11-25','2013-12-05');
    
    ;WITH n(n) AS 
    (
      SELECT ROW_NUMBER() OVER (ORDER BY [object_id])-1 FROM sys.all_columns
    ),
    d(n,f,t,md,bp,ep) AS 
    (
      SELECT n.n, d.from_date, d.to_date, 
        DATEDIFF(MONTH, d.from_date, d.to_date),
        DATEADD(MONTH, n.n, DATEADD(DAY, 1-DAY(from_date), from_date)),
        DATEADD(DAY, -1, DATEADD(MONTH, 1, DATEADD(MONTH, n.n, 
          DATEADD(DAY, 1-DAY(from_date), from_date))))
     FROM n INNER JOIN @d AS d 
     ON d.to_date >= DATEADD(MONTH, n.n-1, d.from_date)
    )
    SELECT original_from_date = f, original_to_date = t, 
      new_from_date = CASE n WHEN 0  THEN f ELSE bp END,
      new_to_date   = CASE n WHEN md THEN t ELSE ep END 
    FROM d WHERE md >= n
    ORDER BY original_from_date, new_from_date;
    

    Results:

    original_from_date   original_to_date   new_from_date   new_to_date
    ------------------   ----------------   -------------   -----------
    2013-11-25           2013-12-05         2013-11-25      2013-11-30
    2013-11-25           2013-12-05         2013-12-01      2013-12-05
    

    SQLFiddle demo with longer date ranges and leap years

    0 讨论(0)
  • 2020-12-06 03:38

    If you are operating in a dimensional data warehouse, utilize the date dimension. Otherwise, use CTE.

    WITH cte AS
    (SELECT from_date
          , to_date
          , from_date AS mo_from_date
          , DATEADD(day, day(from_date)* -1 + 1, from_date) AS bom_date
       FROM DateTable
    UNION ALL
    SELECT from_date
         , to_date
         , DATEADD(month,1,bom_date)
         , DATEADD(month,1,bom_date)
      FROM cte
     where DATEADD(month,1,mo_from_date) < to_date
    )
    SELECT mo_from_date
         , CASE when to_date < DATEADD(month,1,bom_date) THEN
               to_date
           ELSE
               DATEADD(day, -1, DATEADD(month,1,bom_date))
           END AS mo_to_date
      FROM cte
    
    0 讨论(0)
提交回复
热议问题