计算日数而不重复

时间:2016-04-13 04:16:07

标签: sql-server sql-server-2012

假设网络上有以下数据:

Id  Start Date   End Date
1   2016-02-12   2016-02-19
2   2016-02-15   2016-02-22
3   2016-03-14   2016-03-20
4   2016-03-12   2016-03-22

我想计算没有日期重复的日期编号。 例如 从开始到结束的第一行日计数是8天 对于从开始到结束的第二行日计数是8天,但它与第一​​行有4天重叠,我不想计算它。 第三天的日数是......

2 个答案:

答案 0 :(得分:1)

我不确定您是想要每行的天数还是仅需要总天数,因此我将展示一种方法来获取这两个选项:

首先,创建并填充样本表:

DECLARE @Table as TABLE
(
    t_Id int identity(1,1),
    t_start date,
    t_end date
)

INSERT INTO @Table (t_start, t_end) VALUES
('2016-02-12', '2016-02-19'),
('2016-02-15', '2016-02-22'),
('2016-03-14', '2016-03-20'),
('2016-03-12', '2016-03-22')

现在,要获得每行的总和,省略行与上一行重叠的天数,您可以执行以下操作:

使用CTELAG()窗口函数来获取上一行的结束日期, 并使用ISNULL获取最小日期值,如果它是第一行:

;WITH CTE AS
(
    SELECT t_Id, t_start, t_end, ISNULL(LAG(t_end) OVER (ORDER BY t_start), '0001-01-01') As prev_end
    FROM @Table 
)

从该CTE中选择,使用CASE查看前一条记录是否与当前记录重叠。如果是,则从计数中减去重叠天数:

SELECT  t_Id, 
        t_start, 
        t_end, 
        CASE WHEN prev_end < t_start THEN
            DATEDIFF(DAY, t_start, t_end)
        ELSE
            DATEDIFF(DAY, t_start, t_end) - DATEDIFF(DAY, t_start, prev_end)
        END As number_of_days
FROM CTE

结果:

t_Id        t_start    t_end      number_of_days
----------- ---------- ---------- --------------
1           2016-02-12 2016-02-19 7
2           2016-02-15 2016-02-22 3
4           2016-03-12 2016-03-22 10
3           2016-03-14 2016-03-20 -2 -- note that the prev row ends after this one.

要获得总天数,您只需将第二个查询包装在另一个cte中并选择sum(number_of_days)

;WITH CTE1 AS
(
    SELECT t_Id, t_start, t_end, LAG(t_end) OVER (ORDER BY t_start) As prev_end
    FROM @Table 
), CTE2 As
(
    SELECT  t_Id, 
            t_start, 
            t_end, 
            CASE WHEN ISNULL(prev_end, '0001-01-01') < t_start THEN
                DATEDIFF(DAY, t_start, t_end)
            ELSE
                DATEDIFF(DAY, t_start, t_end) - DATEDIFF(DAY, t_start, prev_end)

            END As number_of_days
    FROM CTE1
)

SELECT SUM(number_of_days) 
FROM CTE2

结果是18。

答案 1 :(得分:0)

INSERT INTO dbo.Duration(startDate,endDate) VALUES('2007-05-06,'2007-05-07');
SELECT DATEDIFF(day,startDate,endDate) AS 'Duration' FROM dbo.WhatEver;

返回:1