Search code examples
sqlsql-servert-sqlsql-server-2017

Count days inside date period, count the first 7 days separately


I use SQL Server 2017 and have a table with date periods with a "From date" and a "To date" columns

After I have selected all date periods that overlap with a chosen date period I want to count only the number of days that are inside the chosen date period. I also want to count the first 7 days separate from the remaining days (only the days that fall inside the chosen period).

example:

Chosen period 2022-01-01 to 2022-01-31

SELECT * FROM Table
WHERE [From date] <= '2022-01-01'
AND [To Date] >= '2022-01-31'
ID From date To date Comment
1 2021-12-26 2022-02-09 cut off from and to date
2 2022-01-21 2022-02-09 cut off to date
3 2022-01-10 2022-01-14 no cut off
4 2021-01-15 2022-02-11 cut off from date
5 2020-05-10 2020-10-20 outside chosen period

Wanted results:

ID from date To date first 7 days remaining days Comment
1 2022-01-01 2022-01-31 1 30 cut off from and to date
2 2022-01-21 2022-01-31 7 4 cut off to date
3 2022-01-10 2022-01-14 5 0 no cut off
4 2022-01-01 2022-01-31 0 31 cut off from date

Only the ID, [First 7 days] and [Remaining days] columns in the results table are important and the other columns are only shown in the above example for the purpose of clarity.

I have started writing a series of "case when then" using datediff but it feels overly complicated and I hope there is a better way to do it.


Solution

  • select  from_date
           ,to_date
           
           ,datediff(day, from_date, to_date)+1-case when datediff(day,fd_plus_7, to_date) <= 0 then 0
                 when datediff(day,fd_plus_7, to_date) >= day_max then day_max
                 else datediff(day,fd_plus_7, to_date)+1 end as first_7_days
           
           ,case when datediff(day,fd_plus_7, to_date) <= 0 then 0
                 when datediff(day,fd_plus_7, to_date) >= day_max then day_max
                 else datediff(day,fd_plus_7, to_date)+1 end as remaining_days  
    
           ,Comment  
    from         
            (    
            select *
                   ,datediff(day, min(from_date) over(order by from_date) ,max(to_date) over(order by to_date desc)) + 1 as day_max  
            from   (
                    select *
                           ,case when [From date] < '2022-01-01' then '2022-01-01' else [From date]  end as from_date
                           ,case when [To date]   > '2022-01-31' then '2022-01-31' else [To date]    end as to_date  
                           ,dateadd(day, 7, [From date]) as fd_plus_7
                    from t
                    where [From date] <= '2022-01-31'
                      and [To date]   >= '2022-01-01'
                  ) t ) t
    order by ID
    
    from_date to_date first_7_days remaining_days Comment
    2022-01-01 00:00:00.000 2022-01-31 00:00:00.000 0 31 cut off from and to date
    2022-01-21 00:00:00.000 2022-01-31 00:00:00.000 7 4 cut off to date
    2022-01-10 00:00:00.000 2022-01-14 00:00:00.000 5 0 no cut off
    2022-01-01 00:00:00.000 2022-01-31 00:00:00.000 0 31 cut off from date

    Fiddle