Sql-server – Sum date between two date and group by month

date mathsql serversql-server-2012

I have a table as below:

Name  Start Date  End Date
Joe   20/04/2021  20/05/2021
John  01/05/2021  28/05/2021

I am using a SQL table-valued function to return a table that has 2 columns: Month and Count total Date of this month.

Example:

  • Joe: 10 days in Apr, 20 days in May
  • John: 28 days in May

Finally I will return a new table

Month Count
4 10
5 48

I tried to use datediff and datepart to group by month, but don't know how to sum after group. Is there any way to do this?

Besides, I want to add filter from date and to date.

Best Answer

WITH 
-- Generate months list
cte1 AS ( SELECT MIN(MONTH([Start Date])) [Month], 
                 MAX(MONTH([End Date])) LastMonth, 
                 MIN(YEAR([Start Date])) [Year]
          FROM test
          UNION ALL
          SELECT [Month] + 1, 
                 LastMonth,
                 [Year]
          FROM cte1
          WHERE [Month] < LastMonth ),
-- Convert months list to start-end list
cte2 AS ( SELECT DATEFROMPARTS([Year], [Month], 1) MonthStart,
                 EOMONTH(DATEFROMPARTS([Year], [Month], 1)) MonthEnd,
                 [Month]
          FROM cte1 )
-- Get needed data
SELECT cte2.[Month],
       SUM(1 + DATEDIFF(day, CASE WHEN test.[Start Date] < cte2.MonthStart
                                  THEN cte2.MonthStart
                                  ELSE test.[Start Date] END,
                             CASE WHEN test.[End Date] > cte2.MonthEnd
                                  THEN cte2.MonthEnd
                                 ELSE test.[End Date] END )) [Count]
FROM test
          -- join only overlapped periods
JOIN cte2 ON test.[Start Date] <= cte2.MonthEnd
         AND cte2.MonthStart <= test.[End Date]
GROUP BY cte2.[Month];

https://dbfiddle.uk/?rdbms=sqlserver_2014&fiddle=c2d6d92223f6516d78550a021cd5c3ce

The query assumes that all periods belongs the same year. Of course it can be simplified. The period length from '2021-04-20' to '2021-04-30' (inclusive) is 11 days, not 10.

I want to add filter from date and to date

This affects only cte1 (generate the calendar based not on table data but on needed period dates) and, if you want to filter some month partially (not from first day till the last day of month) on cte2. Main query will be filtered automatically due to ON clause expression.