Reputation: 21
I have a table with customer records, with each customer having a start date and end date. I'm looking for the most efficient way to convert this into a table that counts the number of active customers for each day. For example:
Existing table (Table A):
Customer - Start Date - End Date
A - 1/1/2017 - 1/3/2017
B - 1/2/2017 - 1/5/2017
What I need (Table B):
Date - Customer_Count
1/1/2017 - 1
1/2/2017 - 2
1/3/2017 - 2
1/4/2017 - 1
1/5/2017 - 1
The method I'm using right now is simply joining a date reference table to the customer table, and then grouping by the reference date column. While this method works, the customer table is very large, and there are additional conditions I want to be able to apply (i.e., the geography of the customer, product, etc.) which will additionally impact performance.
Appreciate the help!
Upvotes: 1
Views: 647
Reputation: 81970
A tally/calendar table would do the trick, but an ad-hoc tally table in concert with a Cross Apply may help as well
Example
Select Date
,Customer_Count = count(*)
From YourTable A
Cross Apply (
Select Top (DateDiff(DD,[Start Date] ,[End Date] )+1) Date=DateAdd(DAY,-1+Row_Number() Over (Order By (Select Null)),[Start Date])
From master..spt_values
) B
Group By Date
Order By Date
Returns
Date Customer_Count
2017-01-01 1
2017-01-02 2
2017-01-03 2
2017-01-04 1
2017-01-05 1
Upvotes: 1
Reputation: 13959
You can generate dates using custom table and the do cross apply as below:
select RowN as [Date], count(*) as Customer_Count from #yourcust cross apply
(
select top (datediff(day, startdate, enddate)+1) rowN = dateadd(day, row_number() over (order by s1.name) -1 , startdate) from master..spt_values s1,master..spt_values s2
) a
group by RowN
Output
+------------+----------------+
| Date | Customer_Count |
+------------+----------------+
| 2017-01-01 | 1 |
| 2017-01-02 | 2 |
| 2017-01-03 | 2 |
| 2017-01-04 | 1 |
| 2017-01-05 | 1 |
+------------+----------------+
Upvotes: 1