递归遍历SQL表并根据开始和结束日期查找间隔

时间:2018-09-21 01:12:32

标签: sql sql-server tsql

我有一个包含雇员ID,StartDateTime和EndDatetime的SQL表,如下所示:

CREATE TABLE Sample
(
    SNO INT,
    EmployeeID NVARCHAR(10),
    StartDateTime DATE,
    EndDateTime DATE
)

INSERT INTO Sample
VALUES
( 1, 'xyz', '2018-01-01', '2018-01-02' ), 
( 2, 'xyz', '2018-01-03', '2018-01-05' ), 
( 3, 'xyz', '2018-01-06', '2018-02-01' ), 
( 4, 'xyz', '2018-02-15', '2018-03-15' ), 
( 5, 'xyz', '2018-03-16', '2018-03-19' ),
( 6, 'abc', '2018-01-16', '2018-02-25' ),
( 7, 'abc', '2018-03-08', '2018-03-19' ),
( 8, 'abc', '2018-02-26', '2018-03-01' )

我希望结果显示为

EmployeeID  |  StartDateTime  |  EndDateTime
------------+-----------------+---------------
   xyz      |  2018-01-01     |  2018-02-01
   xyz      |  2018-02-15     |  2018-03-19
   abc      |  2018-01-16     |  2018-03-01
   abc      |  2018-03-08     |  2018-03-19

基本上,我想递归查看每位员工的记录,并确定Start和EndDates的连续性,并制作一组连续的日期记录。

我写的查询如下:

SELECT * 
FROM dbo.TestTable T1 
LEFT JOIN dbo.TestTable t2 ON t2.EmpId = T1.EmpId
WHERE t1.EndDate = DATEADD(DAY, -1, T2.startdate)

看看是否可以从输出中解密某些内容以寻找模式。后来意识到,使用上述方法,我需要多次连接同一张表才能获得所需的输出。

此外,在某些情况下,可能存在多个员工记录,因此我需要指导以有效方式获得此期望的输出。

非常感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

这将为您完成。使用递归CTE获取所有相邻行,然后获取每个开始日期的最高结束日期,然后获得每个结束日期的第一个开始日期。

;with cte as (
    select EmployeeID, StartDateTime, EndDateTime 
    from sample s
    union all
    select CTE.EmployeeID, CTE.StartDateTime, s.EndDateTime
    from sample s
    join cte on cte.EmployeeID=s.EmployeeID and s.StartDateTime=dateadd(d,1,CTE.EndDateTime)
)
select EmployeeID, Min(StartDateTime) as StartDateTime, EndDateTime from (
    select EmployeeID, StartDateTime, Max(EndDateTime) as EndDateTime from cte
    group by EmployeeID, StartDateTime
) q group by EmployeeID, EndDateTime

答案 1 :(得分:1)

您可以使用它。

WITH T AS (
    SELECT  S1.SNO, 
            S1.EmployeeID, 
            S1.StartDateTime, 
            ISNULL(S2.EndDateTime, S1.EndDateTime) EndDateTime,
            ROW_NUMBER() OVER(PARTITION BY S1.EmployeeId ORDER BY S1.StartDateTime) 
                - ROW_NUMBER() OVER(PARTITION BY S1.EmployeeId, CASE WHEN S2.StartDateTime IS NULL THEN 0 ELSE 1 END  ORDER BY S1.StartDateTime ) RN,
            ROW_NUMBER() OVER(PARTITION BY S1.EmployeeId, ISNULL(S2.EndDateTime, S1.EndDateTime) ORDER BY S1.EmployeeId, S1.StartDateTime) RN_END
    FROM Sample S1
        LEFT JOIN Sample S2 ON DATEADD(DAY,1,S1.EndDateTime) = S2.StartDateTime
)
SELECT EmployeeID,  MIN(StartDateTime) StartDateTime,MAX(EndDateTime) EndDateTime FROM T
WHERE RN_END = 1
GROUP BY EmployeeID, RN
ORDER BY EmployeeID DESC, StartDateTime

结果:

EmployeeID StartDateTime EndDateTime
---------- ------------- -----------
xyz        2018-01-01    2018-02-01
xyz        2018-02-15    2018-03-19
abc        2018-01-16    2018-03-01
abc        2018-03-08    2018-03-19