合并缺席期

时间:2017-09-29 13:33:41

标签: sql sql-server sql-server-2012

我有以下数据集:

;with Data AS
(
select '001' AS PERSONNUM,'2017-09-18 00:00:00.000' AS START,'2017-09-21 00:00:00.000' AS [END]
UNION
select '001','2017-09-22 00:00:00.000' AS START,'2017-09-22 00:00:00.000' AS [END]
UNION
select '002','2017-09-18 00:00:00.000' AS START,'2017-09-20 00:00:00.000' AS [END]
UNION
select '002','2017-09-22 00:00:00.000' AS START,'2017-09-22 00:00:00.000' AS [END]
)
select * from Data

enter image description here

如果某个员工(PERSONNUM)的START列与下一行的END列和上一列的END列之间的天数差异等于1,我需要合并记录。在我的示例中,对于人员' 001'记录应该合并,对于人员#002;' - 没有变化。

因此,预期结果如下:

enter image description here

提前谢谢!

1 个答案:

答案 0 :(得分:2)

沿着这条线的东西...基本上直接来自Itzik Ben-Gan's New Solution to the Packing Intervals Problem

IF OBJECT_ID('tempdb..#TestData', 'U') IS NOT NULL 
DROP TABLE #TestData;

CREATE TABLE #TestData (
    PersonId CHAR(3),
    BegDT DATETIME,
    EndDT DATETIME
    );
INSERT #TestData(PersonId, BegDT, EndDT) VALUES
    (1, '20151231 08:00:00', '20151231 08:30:00'),
    (1, '20151231 08:30:00', '20151231 09:00:00'),
    (1, '20151231 09:00:00', '20151231 09:30:00'),
    (1, '20151231 10:00:00', '20151231 11:00:00'),
    (1, '20151231 10:30:00', '20151231 12:00:00'),
    (1, '20151231 11:30:00', '20151231 12:30:00'),
    (2, '20151231 08:00:00', '20151231 10:30:00'),
    (2, '20151231 08:30:00', '20151231 10:00:00'),
    (2, '20151231 09:00:00', '20151231 09:30:00'),
    (2, '20151231 11:00:00', '20151231 11:30:00'),
    (2, '20151231 11:32:00', '20151231 12:00:00'),
    (2, '20151231 12:04:00', '20151231 12:30:00'),
    (3, '20151231 08:00:00', '20151231 09:00:00'),
    (3, '20151231 08:00:00', '20151231 08:30:00'),
    (3, '20151231 08:30:00', '20151231 09:00:00'),
    (3, '20151231 09:30:00', '20151231 09:30:00');

WITH
    cte_MPE AS (
        SELECT 
            td.PersonId, td.BegDT, td.EndDT,
            MaxPrevEnd = MAX(td.EndDT) OVER (PARTITION BY td.PersonId ORDER BY td.BegDT, td.EndDT ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING)
        FROM
            #TestData td
        ),
    cte_DivGroup AS (
        SELECT 
            m.PersonId, m.BegDT, m.EndDT, m.MaxPrevEnd,
            DivGroup = SUM(x.NewBeg) OVER (PARTITION BY m.PersonId ORDER BY m.BegDT, m.EndDT ROWS UNBOUNDED PRECEDING)
        FROM
            cte_MPE m
            CROSS APPLY ( VALUES (IIF(m.BegDT <= m.MaxPrevEnd, NULL, 1)) ) x (NewBeg)
        )
SELECT 
    dg.PersonId, 
    BegDT = MIN(dg.BegDT), 
    EndDT = MAX(dg.EndDT)
FROM
    cte_DivGroup dg
GROUP BY
    dg.PersonId,
    dg.DivGroup
ORDER BY
    dg.PersonId;

结果...

PersonId BegDT                   EndDT
-------- ----------------------- -----------------------
1        2015-12-31 08:00:00.000 2015-12-31 09:30:00.000
1        2015-12-31 10:00:00.000 2015-12-31 12:30:00.000
2        2015-12-31 08:00:00.000 2015-12-31 10:30:00.000
2        2015-12-31 11:00:00.000 2015-12-31 11:30:00.000
2        2015-12-31 11:32:00.000 2015-12-31 12:00:00.000
2        2015-12-31 12:04:00.000 2015-12-31 12:30:00.000
3        2015-12-31 08:00:00.000 2015-12-31 09:00:00.000
3        2015-12-31 09:30:00.000 2015-12-31 09:30:00.000