计算两个日期列之间包含日期的次数

时间:2016-06-17 20:40:21

标签: sql-server

我有一张看起来像这样的表

ID  start_dt    end_dt
--------------------------
1   1951-12-05  1951-12-21
2   1951-12-19  1951-12-31
3   1957-12-05  1957-12-19
4   1995-12-06  1995-12-20
5   1996-06-24  1996-07-08
6   1997-05-12  1997-05-26
7   1997-10-07  1997-10-21
8   1997-12-25  1998-01-08
9   1998-01-19  1998-02-02
10  1998-08-05  1998-08-19

我想知道start_dtend_dt之间每个日期的包含次数。

从我的例子中,结果集应该看起来像这样

date         count
------------------
1951-12-05   1
1951-12-06   1
...
1951-12-19   2
1951-12-20   2
1951-12-21   2
...
1998-08-19   1

最好的方法是什么?

编辑:为了澄清,我需要在日期范围内(start_dt和end_dt之间)至少出现一次的每个日期,以便在我的结果集中获得一行,并且我希望此日期适合的范围数量在它旁边

希望这会有所帮助

3 个答案:

答案 0 :(得分:1)

当您需要将2个值(范围)转换为一系列行时,您可以使用数字表格(如果您不熟悉这个想法,请参阅Aaron Bertrand的The SQL Server Numbers Table文章)。

我使用的是更短更简单的数据,但您应该明白这一点。

declare @dates table (id int not null, start_dt date not null, end_dt date not null)
insert @dates values (1, '20160601', '20160603'),
                     (2, '20160603', '20160605'),
                     (3, '20160610', '20160612')

;with cte as (
    select
        row_number() over (order by so1.object_id) - 1 as n
    from
        sys.objects so1
            cross join sys.objects so2
)
select  
    dateadd(d, c.n, d.start_dt) as [date],
    count(*)
from
    @dates d
        join cte c on dateadd(d, c.n, d.start_dt) <= d.end_dt
group by 
    dateadd(d, c.n, d.start_dt)
order by 
    dateadd(d, c.n, d.start_dt)

答案 1 :(得分:0)

您可以使用CTE

WITH CTE AS(SELECT start_dt AS dates FROM Table
            UNION ALL
            SELECT end_dt AS dates FROM Table)
SELECT CAST(dates as DATE) as Date, COUNT(dates) AS Count
FROM CTE c
GROUP BY c.dates
order by Count desc

如果您的列属于DATETIME数据类型,或许您需要更广泛的内容。这种方式将GROUP BY整天:

WITH CTE AS(SELECT CAST(start_dt AS DATE) AS dates FROM Table
            UNION ALL
            SELECT CAST(end_dt AS DATE) AS dates FROM Table)
SELECT Dates as Date, COUNT(Dates) AS Count
FROM CTE c
GROUP BY c.dates
order by Count desc

答案 2 :(得分:0)

如果在sys.objectsstart_dt之间不超过几天(<80左右,具体取决于end_dt表),您可以使用此方法(受到启发)里斯&#39;。)

DECLARE @dates TABLE (id int not null, start_dt date not null, end_dt date not null)
INSERT @dates VALUES
    (1, '1951-12-05', '1951-12-21'),
    (2, '1951-12-19', '1951-12-31'),
    (3, '1957-12-05', '1957-12-19'),
    (4, '1995-12-06', '1995-12-20'),
    (5, '1996-06-24', '1996-07-08'),
    (6, '1997-05-12', '1997-05-26'),
    (7, '1997-10-07', '1997-10-21'),
    (8, '1997-12-25', '1998-01-08'),
    (9, '1998-01-19', '1998-02-02'),
    (10, '1998-08-05', '1998-08-19');

WITH RawData AS (
SELECT  
    DATEADD(d, n.n, d.start_dt) AS [date]
FROM @dates d
INNER JOIN (
    SELECT ROW_NUMBER() OVER (ORDER BY object_id) - 1 AS n FROM sys.objects
    ) n ON DATEADD(d, n.n, d.start_dt) <= d.end_dt
)
SELECT [date], COUNT(*) [count]
FROM RawData
GROUP BY [date]
ORDER BY [date]

我认为即使有1000个日期范围,这也可能需要很长时间。也许您正在使用包含更多字段的表,甚至缺少某些索引?