I’m having trouble writing a recursive function that would count the number of active clients on any given day.
Say I have a table like this:
Client | Start Date | End Date |
---|---|---|
1 | 1-Jan-22 | |
2 | 1-Jan-22 | 3-Jan-22 |
3 | 3-Jan-22 | |
4 | 4-Jan-22 | 5-Jan-22 |
5 | 4-Jan-22 | 6-Jan-22 |
6 | 7-Jan-22 | 9-Jan-22 |
I want to return a table that would look like this:
Date | NumActive |
---|---|
1-Jan-22 | 2 |
2-Jan-22 | 2 |
3-Jan-22 | 3 |
4-Jan-22 | 4 |
5-Jan-22 | 4 |
6-Jan-22 | 3 |
7-Jan-22 | 3 |
8-Jan-22 | 3 |
9-Jan-22 | 4 |
Is there a way to do this? Ideally, I’d have a fixed start date and go to today’s date.
Some pieces I have tried:
Creating a recursive date table
Truncated to Feb 1, 2022 for simplicity:
WITH DateDiffs AS ( SELECT DATEDIFF(DAY, '2022-02-02', GETDATE()) AS NumDays ) , Numbers(Numbers) AS ( SELECT MAX(NumDays) FROM DateDiffs UNION ALL SELECT Numbers-1 FROM Numbers WHERE Numbers > 0 ) , Dates AS ( SELECT Numbers , DATEADD(DAY, -Numbers, CAST(GETDATE() -1 AS DATE)) AS [Date] FROM Numbers )
I would like to be able to loop over the dates in that table, such as by modifying the query below for each date, such as by @loopdate. Then UNION ALL it to a larger final query. I’m now stuck as to how I can run the query to count the number of active users:
SELECT COUNT(Client) FROM clients WHERE [Start Date] >= @loopdate AND ([End Date] <= @loopdate OR [End Date] IS NULL)
Thank you!
Advertisement
Answer
You don’t need anything recursive in this particular case, you need as a minimum a list of dates in the range you want to report on, ideally a permanent calendar table.
for purposes of demonstration you can create something on the fly, and use it like so, with the list of dates something you outer join to:
with dates as ( select top(9) Convert(date,DateAdd(day, -1 + Row_Number() over(order by (select null)), '20220101')) dt from master.dbo.spt_values ) select d.dt [Date], c.NumActive from dates d outer apply ( select Count(*) NumActive from t where d.dt >= t.StartDate and (d.dt <= t.EndDate or t.EndDate is null) )c
See this Demo Fiddle