查找日期之间的差距和重叠

Find a gap and overlap between dates

我正在构建一份报告,该报告将捕捉负责任的开始日期和结束日期中的所有差距和重叠。

想法是有一个列(状态),它将有 5 个输出(我知道,一条记录可能有多个场景,但我需要按以下顺序分配它们:

  1. No Responsible - 当根本没有关联的 Responsible(ResponsibleId 或 ResponsibleName 为 NULL)
  2. 无当前负责人 - 当跨所有与客户关联的记录时,ResponsibleEndDate 不为 NULL(表示当前)。
  3. Overlap - 当前一个负责人的 ResponsibleEndDate 与下一个负责人的 ResponsibleStartDate 重叠时。
  4. Gap - 当上一个负责人的 ResponsibleEndDate 和下一个负责人的 ResponsibleStartDate 之间存在差距时。
  5. 有效 - 当前任负责人的 ResponsibleEndDate 与后任负责人的 ResponsibleStartDate 相差 1 天时。
CREATE TABLE example
(ClientId INT, ClientName VARCHAR(100), ResponsibleId INT, ResponsibleName VARCHAR(100), ResponsibleStartDate DATE, ResponsibleEndDate DATE);

INSERT INTO example
VALUES
(123, 'John Smith', NULL, NULL, NULL, NULL),
(234, 'Thomas Anderson', 12345, 'Tom Cruise', '2019-04-13', '2020-09-15'),
(234, 'Thomas Anderson', 23456, 'John Travolta', '2020-09-16', '2022-01-15'),
(234, 'Thomas Anderson', 37890, 'Van Damm', '2022-01-16', NULL),
(345, 'Mary Tron', NULL, NULL, NULL, NULL),
(456, 'Jackie Chan', 56789, 'Leo Messi', '2018-05-18', '2022-01-18'),
(567, 'Cristiano Ronaldo', 12345, 'Tom Cruise', '2019-05-28', '2021-08-20'),
(567, 'Cristiano Ronaldo', 37890, 'Van Damm', '2021-07-15', '2022-01-15'),
(567, 'Cristiano Ronaldo', 17956, 'Harry Potter', '2022-01-25', NULL)

SELECT * FROM example

我需要的输出:

ClientId ClientName ResponsibleId ResponsibleName ResponsibleStartDate ResponsibleEndDate Status
123 John Smith NULL NULL NULL NULL No Responsible
234 Thomas Anderson 12345 Tom Cruise 2019-04-13 2020-09-15 Valid
234 Thomas Anderson 23456 John Travolta 2020-09-16 2022-01-15 Valid
234 Thomas Anderson 37890 Van Damm 2022-01-16 NULL Valid
345 Mary Tron NULL NULL NULL NULL No Responsible
456 Jackie Chan 56789 Leo Messi 2018-05-18 2022-01-18 No Current Responsible
567 Cristiano Ronaldo 12345 Tom Cruise 2019-05-28 2021-08-20 Overlap
567 Cristiano Ronaldo 37890 Van Damm 2021-07-15 2022-01-15 Gap
567 Cristiano Ronaldo 17956 Harry Potter 2022-01-25 NULL Gap

我能达到的条件只有第一个:

SELECT *,
      CASE      
        WHEN ResponsibleId IS NULL THEN 'No Responsible'      
      END AS [Status]      
FROM example

这是一个好的开始:

declare @example table
(ClientId INT, ClientName VARCHAR(100), ResponsibleId INT, ResponsibleName VARCHAR(100), ResponsibleStartDate DATE, ResponsibleEndDate DATE);

INSERT INTO @example
VALUES
(123, 'John Smith', NULL, NULL, NULL, NULL),
(234, 'Thomas Anderson', 12345, 'Tom Cruise', '2019-04-13', '2020-09-15'),
(234, 'Thomas Anderson', 23456, 'John Travolta', '2020-09-16', '2022-01-15'),
(234, 'Thomas Anderson', 37890, 'Van Damm', '2022-01-16', NULL),
(345, 'Mary Tron', NULL, NULL, NULL, NULL),
(456, 'Jackie Chan', 56789, 'Leo Messi', '2018-05-18', '2022-01-18'),
(567, 'Cristiano Ronaldo', 12345, 'Tom Cruise', '2019-05-28', '2021-08-20'),
(567, 'Cristiano Ronaldo', 37890, 'Van Damm', '2021-07-15', '2022-01-15'),
(567, 'Cristiano Ronaldo', 17956, 'Harry Potter', '2022-01-25', NULL)
;WITH CTE AS
(
SELECT *,
    --ROW_NUMBER() OVER(PARTITION BY ClientName ORDER BY COALESCE(ResponsibleStartDate, ResponsibleEndDate)) DN,
    LEAD(ResponsibleStartDate)OVER(PARTITION BY ClientName ORDER BY COALESCE(ResponsibleStartDate, ResponsibleEndDate)) NEXT_START_DATE,
    LAG(ResponsibleEndDate)OVER(PARTITION BY ClientName ORDER BY COALESCE(ResponsibleStartDate, ResponsibleEndDate)) PREV_END_DATE
FROM @example
)
select *,
    CASE 
        WHEN ResponsibleName IS NULL THEN 'No Responsible'
        WHEN PREV_END_DATE IS NOT NULL AND ResponsibleStartDate < PREV_END_DATE then 'OVERLAP'
        WHEN PREV_END_DATE IS NOT NULL AND DATEDIFF(dd,PREV_END_DATE, ResponsibleStartDate) = 1 then 'VALID'
        WHEN PREV_END_DATE IS NULL then 'VALID'
        WHEN PREV_END_DATE IS NOT NULL AND ResponsibleStartDate > PREV_END_DATE then 'GAP'
        ELSE 'CASE'
    end [STATUS]
from 
    CTE;