在发生中断之前的日期范围内选择最早的日期

时间:2019-03-05 22:12:20

标签: sql-server gaps-and-islands

我一直在寻找一种解决方案,以从一系列日期范围中获取最新的开始日期。我在StackOverflow以及其他网站上都找到了类似的主题,但都不适用于我的特定情况。

这是我数据库中数据的两个示例:

示例1

Start Date | End Date
-----------|-----------
8/26/2006  | 5/31/2016
6/1/2016   | 12/31/2017
1/1/2018   | NULL

对于此示例,我期望查询的结果为:8/26/2006。这是因为开始和结束日期一直延续到原始开始日期。

示例2

Start Date | End Date
-----------|-----------
7/6/2014   | 11/30/2014
1/1/2019   | NULL

对于此示例,我期望查询的结果为:1/1/2019。这是因为在2014年11月30日到2019年1月1日之间会有一个休息时间。

我不需要返回所有日期甚至结束日期的列表。我只需要最早的开始日期,然后再打破日期范围即可。

我猜测我需要的是递归CTE来遍历记录,例如:

WITH CTE AS
  (
    SELECT
      T1.StartDate
     ,T1.EndDate
    FROM
      ExampleTable AS T1
    LEFT JOIN
      ExampleTable AS T2
        ON
        T1.EmployeeID = T2.EmployeeID
          AND T1.StartDate - 1 = T2.EndDate
    WHERE
      T1.EmployeeID = @EmployeeID
    UNION ALL
    SELECT
      C.EmployeeID
     ,C.StartDate
     ,T2.EndDate
    FROM
      CTE AS C
    JOIN
      ExampleTable AS T2
        ON
        C.EmployeeID = T2.EmployeeID
          AND T2.StartDate - 1 = C.EndDate
  )
SELECT
  StartDate
 ,NULLIF(MAX(ISNULL(EndDate, '32121231')), '32121231') AS EndDate
FROM
  CTE
GROUP BY
  StartDate;

但是没有运气。它总是返回示例1或2中列出的所有日期范围。有人可以帮忙吗?

1 个答案:

答案 0 :(得分:1)

这似乎是获得结果的最简单方法:

SELECT TOP 1 StartDate
FROM YourTable
ORDER BY CASE WHEN LAG(EndDate) OVER (ORDER BY StartDate) = DATEADD(DAY,-1,StartDate) THEN 1 ELSE 0 END,
         StartDate DESC;

因此,为了您的数据:

WITH VTE AS(
    SELECT CONVERT(date, StartDate,101) AS StartDate,
           CONVERT(date, EndDate,101) AS EndDate
    FROM (VALUES('7/6/2014','11/30/2014'),
                ('1/1/2019',NULL)) V(StartDate, EndDate))
SELECT TOP 1 StartDate
FROM VTE
ORDER BY CASE WHEN LAG(EndDate) OVER (ORDER BY StartDate) = DATEADD(DAY,-1,StartDate) THEN 1 ELSE 0 END,
         StartDate DESC;

WITH VTE AS(
    SELECT CONVERT(date, StartDate,101) AS StartDate,
           CONVERT(date, EndDate,101) AS EndDate
    FROM (VALUES('8/26/2006','5/31/2016'),
                ('6/1/2016 ','12/31/2017'),
                ('1/1/2018 ',NULL)) V(StartDate, EndDate))
SELECT TOP 1 StartDate
FROM VTE
ORDER BY CASE WHEN LAG(EndDate) OVER (ORDER BY StartDate) = DATEADD(DAY,-1,StartDate) THEN 1 ELSE 0 END,
         StartDate DESC;