I need to count the number of campaigns per day based on the start and end dates of the campaigns
Input Table:
Campaign name | Start date | End date |
---|---|---|
Campaign A | 2022-07-10 | 2022-09-25 |
Campaign B | 2022-08-06 | 2022-10-07 |
Campaign C | 2022-07-30 | 2022-09-10 |
Campaign D | 2022-08-26 | 2022-10-24 |
Campaign E | 2022-07-17 | 2022-09-29 |
Campaign F | 2022-08-24 | 2022-09-12 |
Campaign G | 2022-08-11 | 2022-10-24 |
Campaign H | 2022-08-26 | 2022-11-22 |
Campaign I | 2022-08-29 | 2022-09-25 |
Campaign J | 2022-08-21 | 2022-11-15 |
Campaign K | 2022-07-20 | 2022-09-18 |
Campaign L | 2022-07-31 | 2022-11-20 |
Campaign M | 2022-08-17 | 2022-10-10 |
Campaign N | 2022-07-27 | 2022-09-07 |
Campaign O | 2022-07-29 | 2022-09-26 |
Campaign P | 2022-07-06 | 2022-09-15 |
Campaign Q | 2022-07-16 | 2022-09-22 |
Out needed (result):
Date | Count unique campaigns |
---|---|
2022-07-02 | 17 |
2022-07-03 | 47 |
2022-07-04 | 5 |
2022-07-05 | 5 |
2022-07-06 | 25 |
2022-07-07 | 27 |
2022-07-08 | 17 |
2022-07-09 | 58 |
2022-07-10 | 23 |
2022-07-11 | 53 |
2022-07-12 | 18 |
2022-07-13 | 29 |
2022-07-14 | 52 |
2022-07-15 | 7 |
2022-07-16 | 17 |
2022-07-17 | 37 |
2022-07-18 | 33 |
How do I need to write the SQL command to get the above result? thanks all
CodePudding user response:
Your sample data doesn't seem to match your desired results, but I think what you're after is this:
DECLARE @Start date, @End date;
-- first, find the earliest and last date:
SELECT @Start = MIN([Start date]), @End = MAX([End date])
FROM dbo.Campaigns;
-- now use a recursive CTE to build a date range,
-- and count the number of campaigns that have a row
-- where the campaign was active on that date:
WITH d(d) AS
(
SELECT @Start
UNION ALL
SELECT DATEADD(DAY, 1, d) FROM d WHERE d < @End
)
SELECT
[Date] = d,
[Count unique campaigns] = COUNT(*)
FROM d
INNER JOIN dbo.Campaigns AS c
ON d.d >= c.[Start date] AND d.d <= c.[End date]
GROUP BY d.d OPTION (MAXRECURSION 32767);
Working example in this fiddle.
CodePudding user response:
In the following solutions we leverage string_split
with combination with replicate to generate new records.
select dt as date
,count(*) as Count_unique_campaigns
from
(
select *
,dateadd(day, row_number() over(partition by Campaign_name order by (select null))-1, Start_date) as dt
from (
select *
from t
outer apply string_split(replicate(',',datediff(day, Start_date, End_date)),',')
) t
) t
group by dt
order by dt
date | Count_unique_campaigns |
---|---|
2022-07-06 | 1 |
2022-07-07 | 1 |
2022-07-08 | 1 |
2022-07-09 | 1 |
2022-07-10 | 2 |
2022-07-11 | 2 |
2022-07-12 | 2 |
2022-07-13 | 2 |
2022-07-14 | 2 |
2022-07-15 | 2 |
2022-07-16 | 3 |
2022-07-17 | 4 |
2022-07-18 | 4 |
2022-07-19 | 4 |
2022-07-20 | 5 |
2022-07-21 | 5 |
2022-07-22 | 5 |
2022-07-23 | 5 |
2022-07-24 | 5 |
2022-07-25 | 5 |
2022-07-26 | 5 |
2022-07-27 | 6 |
2022-07-28 | 6 |
2022-07-29 | 7 |
2022-07-30 | 8 |
2022-07-31 | 9 |
2022-08-01 | 9 |
2022-08-02 | 9 |
2022-08-03 | 9 |
2022-08-04 | 9 |
2022-08-05 | 9 |
2022-08-06 | 10 |
2022-08-07 | 10 |
2022-08-08 | 10 |
2022-08-09 | 10 |
2022-08-10 | 10 |
2022-08-11 | 11 |
2022-08-12 | 11 |
2022-08-13 | 11 |
2022-08-14 | 11 |
2022-08-15 | 11 |
2022-08-16 | 11 |
2022-08-17 | 12 |
2022-08-18 | 12 |
2022-08-19 | 12 |
2022-08-20 | 12 |
2022-08-21 | 13 |
2022-08-22 | 13 |
2022-08-23 | 13 |
2022-08-24 | 14 |
2022-08-25 | 14 |
2022-08-26 | 16 |
2022-08-27 | 16 |
2022-08-28 | 16 |
2022-08-29 | 17 |
2022-08-30 | 17 |
2022-08-31 | 17 |
2022-09-01 | 17 |
2022-09-02 | 17 |
2022-09-03 | 17 |
2022-09-04 | 17 |
2022-09-05 | 17 |
2022-09-06 | 17 |
2022-09-07 | 17 |
2022-09-08 | 16 |
2022-09-09 | 16 |
2022-09-10 | 16 |
2022-09-11 | 15 |
2022-09-12 | 15 |
2022-09-13 | 14 |
2022-09-14 | 14 |
2022-09-15 | 14 |
2022-09-16 | 13 |
2022-09-17 | 13 |
2022-09-18 | 13 |
2022-09-19 | 12 |
2022-09-20 | 12 |
2022-09-21 | 12 |
2022-09-22 | 12 |
2022-09-23 | 11 |
2022-09-24 | 11 |
2022-09-25 | 11 |
2022-09-26 | 9 |
2022-09-27 | 8 |
2022-09-28 | 8 |
2022-09-29 | 8 |
2022-09-30 | 7 |
2022-10-01 | 7 |
2022-10-02 | 7 |
2022-10-03 | 7 |
2022-10-04 | 7 |
2022-10-05 | 7 |
2022-10-06 | 7 |
2022-10-07 | 7 |
2022-10-08 | 6 |
2022-10-09 | 6 |
2022-10-10 | 6 |
2022-10-11 | 5 |
2022-10-12 | 5 |
2022-10-13 | 5 |
2022-10-14 | 5 |
2022-10-15 | 5 |
2022-10-16 | 5 |
2022-10-17 | 5 |
2022-10-18 | 5 |
2022-10-19 | 5 |
2022-10-20 | 5 |
2022-10-21 | 5 |
2022-10-22 | 5 |
2022-10-23 | 5 |
2022-10-24 | 5 |
2022-10-25 | 3 |
2022-10-26 | 3 |
2022-10-27 | 3 |
2022-10-28 | 3 |
2022-10-29 | 3 |
2022-10-30 | 3 |
2022-10-31 | 3 |
2022-11-01 | 3 |
2022-11-02 | 3 |
2022-11-03 | 3 |
2022-11-04 | 3 |
2022-11-05 | 3 |
2022-11-06 | 3 |
2022-11-07 | 3 |
2022-11-08 | 3 |
2022-11-09 | 3 |
2022-11-10 | 3 |
2022-11-11 | 3 |
2022-11-12 | 3 |
2022-11-13 | 3 |
2022-11-14 | 3 |
2022-11-15 | 3 |
2022-11-16 | 2 |
2022-11-17 | 2 |
2022-11-18 | 2 |
2022-11-19 | 2 |
2022-11-20 | 2 |
2022-11-21 | 1 |
2022-11-22 | 1 |
For SQL in Azure and SQL Server 2022 we have a cleaner solution based on [ordinal][4].
"The enable_ordinal argument and ordinal output column are currently supported in Azure SQL Database, Azure SQL Managed Instance, and Azure Synapse Analytics (serverless SQL pool only). Beginning with SQL Server 2022 (16.x) Preview, the argument and output column are available in SQL Server."
select dt as date
,count(*) as Count_unique_campaigns
from
(
select *
,dateadd(day, ordinal-1, Start_date) as dt
from (
select *
from t
outer apply string_split(replicate(',',datediff(day, Start_date, End_date)),',', 1)
) t
) t
group by dt
order by dt