为范围内的每个日期创建一行,并为 SQL 中的记录在日期范围内的每一天加 1

Create a row for each date in a range, and add 1 for each day within a date range for a record in SQL

假设我有一个日期范围,@StartDate = 2022-01-01 和@EndDate = 2022-02-01,这是一个报告期。

此外,我还有客户记录,其中每个客户都有一个 LIVE Date 和一个 ServiceEndDate(或者 ServiceEndDate = NULL,因为他们是持续的客户)

一些客户的生效日期和服务结束日期范围可能会超出报告期范围。我只想报告他们在此期间是客户的天数。

Name LiveDate ServiceEndDate
Tom 2021-10-11 2022-01-13
Mark 2022-11-13 2022-02-15
Andy 2022-01-02 2022-02-10
Rob 2022-01-09 2022-01-14

我想创建一个 table,其中 A 列是日期(在报告期间的每个日期之间迭代),B 列是该日期作为客户的客户数量的总和.

像这样

Date NumberOfCustomers
2022-01-01 2
2022-01-02 3
2022-01-03 3
2022-01-04 3
2022-01-05 3
2022-01-06 3
2022-01-07 3
2022-01-08 3
2022-01-09 4
2022-01-10 4
2022-01-11 4
2022-01-12 4
2022-01-13 4
2022-01-14 3
2022-01-15 3

以此类推直到@EndDate

结束

非常感谢任何帮助,谢谢。

您可以将您的 table 加入包含您需要的所有日期的日历 table:

with calendar as
(select cast('2022-01-01' as datetime) as d
union all select dateadd(day, 1, d)
from calendar
where d < '2022-02-01')
select d as "Date", count(*) as NumberOfCustomers 
from calendar inner join table_name
on d between LiveDate and coalesce(ServiceEndDate, '9999-12-31')
group by d;

Fiddle

我个人建议使用 Tally 而不是 rCTE,因为 Tally 显着 更高效。

SELECT *
INTO dbo.YourTable
FROM (VALUES('Tom ',CONVERT(date,'2021-10-11 '),CONVERT(date,'2022-01-13')),
            ('Mark',CONVERT(date,'  2022-11-13'),CONVERT(date,' 2022-02-15')),
            ('Andy',CONVERT(date,'  2022-01-02'),CONVERT(date,' 2022-02-10')),
            ('Rob ',CONVERT(date,'2022-01-09 '),CONVERT(date,'2022-01-14')))V(Name,LiveDate,ServiceEndDate);
GO
SELECT *
FROM dbo.YourTable;
GO
DECLARE @StartDate date = '20220101',
        @EndDate date = '20220201';

WITH N AS(
    SELECT N
    FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
    SELECT 0 AS I
    UNION ALL
    SELECT TOP (DATEDIFF(DAY, @StartDate, @EndDate)) 
           ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
    FROM N N1, N N2, N N3), --up to 1,000 days
Dates AS(
    SELECT DATEADD(DAY, T.I, @StartDate) AS Date
    FROM Tally T)
SELECT D.Date,
       COUNT(YT.[Name]) AS NumberOfCustomers
FROM Dates D
     LEFT JOIN dbo.YourTable YT ON D.[Date] >= YT.LiveDate
                               AND (D.[Date] <= YT.ServiceEndDate
                                OR  YT.ServiceEndDate IS NULL)
GROUP BY D.[Date]
ORDER BY D.[Date];
GO

DROP TABLE dbo.YourTable;

请注意,结果并未反映您的预期结果,我怀疑您的预期结果是错误的。例如,您有 2 个人生活在 2022-01-01,但是,只有 1 个人在该日期生活:Tom。

此解决方案也永远不会将标记为“实时”(另一个答案中的 rCTE 方法也不会),因为它们的结束日期是 它们的实时日期之前。如果有人可以在开始之前结束服务,我建议你有数据质量问题,你应该在 table 中添加 CHECK CONSTRAINT 以确保 ServiceEndDate>= LiveDate.