【问题标题】:How to determine consecutive date records with overlaps in SQL Server如何在 SQL Server 中确定具有重叠的连续日期记录
【发布时间】:2017-05-22 12:13:03
【问题描述】:

我知道有类似的问题,但没有找到这个具体案例的答案。假设我在表中有以下日期范围(按日期排序):

 StartDate   -   EndDate      DoW
----------------------------------
 2017-01-10  -   2017-01-15    1
 2017-01-16  -   2017-01-19    2
 2017-01-17  -   2017-01-19    3
 2017-01-18  -   2017-01-21    4
 2017-01-22  -   2017-01-28    5

预期结果是TRUE。此集合包含重叠的连续日期记录(之间没有间隙)

 StartDate   -   EndDate      DoW
----------------------------------
 2017-01-10  -   2017-01-15    1
 2017-01-16  -   2017-01-19    2
 2017-01-20  -   2017-01-23    3
 2017-01-24  -   2017-01-26    4
 2017-01-27  -   2017-01-28    5

预期结果是TRUE。该集合包含连续的日期记录(无重叠)

对于这种情况:

StartDate   -   EndDate      DoW
---------------------------------
 2017-01-10  -   2017-01-15    1
 2017-01-17  -   2017-01-19    2
 2017-01-17  -   2017-01-19    3
 2017-01-18  -   2017-01-21    4
 2017-01-22  -   2017-01-28    5

结果应该是FALSE,因为第 1 行和第 2 行之间存在间隙(缺少 2017-01-16)。

提前致谢。

【问题讨论】:

    标签: sql sql-server datetime


    【解决方案1】:

    如果有间隔,它将是结束日期前一天或开始日期后一天。您可以获取此日期列表并检查是否存在空白。这很棘手,因为您不想要这些日期的第一个和最后一个。 . .但是,您可以将阈值设置为 2:

    with d as (
          select dateadd(day, -1, startdate) as dte
          from t
          union all  -- do not remove duplicates!
          select dateadd(day, + 1, enddate) as dte
          from t
         )
    select (case when count(*) > 2 then 'false' else 'true' end)
    from d
    where not exists (select 1
                      from t
                      where d.dte >= t.startdate and
                            d.dte <= t.enddate
                     );
    

    【讨论】:

      【解决方案2】:

      如果顺序与您的示例数据中的一样,您可以试试这个,它使用 LAG() 函数:

      CREATE TABLE TT1 (STARTDATE DATE, ENDDATE DATE, DOW INT);
      

      1)

      INSERT INTO TT1 VALUES ('2017-01-10','2017-01-15',    1);
       INSERT INTO TT1 VALUES ('2017-01-16','2017-01-19',    2);
       INSERT INTO TT1 VALUES ('2017-01-17','2017-01-19',    3);
       INSERT INTO TT1 VALUES ('2017-01-18','2017-01-21',    4);
       INSERT INTO TT1 VALUES ('2017-01-22','2017-01-28',    5);
      
      
      SELECT MIN(CHCK)  AS CHK
      FROM (
              SELECT CASE WHEN DATEDIFF(dd, LAG(ENDDATE) OVER (ORDER BY DOW), STARTDATE) >1 THEN 0 ELSE 1 END AS CHCK
              FROM TT1
             ) A;
      
       DELETE FROM TT1;
      

      输出 1:

      +-----+
      | CHK |
      +-----+
      | 1   |
      +-----+
      

      2)

       INSERT INTO TT1 VALUES ('2017-01-10','2017-01-15',    1);
       INSERT INTO TT1 VALUES ('2017-01-16','2017-01-19',    2);
       INSERT INTO TT1 VALUES ('2017-01-20','2017-01-23',    3);
       INSERT INTO TT1 VALUES ('2017-01-24','2017-01-26',    4);
       INSERT INTO TT1 VALUES ('2017-01-27','2017-01-28',    5);
      
      SELECT MIN(CHCK)  AS CHK
      FROM (
              SELECT CASE WHEN DATEDIFF(dd, LAG(ENDDATE) OVER (ORDER BY DOW), STARTDATE) >1 THEN 0 ELSE 1 END AS CHCK
              FROM TT1
             ) A;
      
       DELETE FROM TT1;
      

      输出 2:

      +-----+
      | CHK |
      +-----+
      | 1   |
      +-----+
      

      3)

       INSERT INTO TT1 VALUES ('2017-01-10','2017-01-15',    1);
       INSERT INTO TT1 VALUES ('2017-01-17','2017-01-19',    2);
       INSERT INTO TT1 VALUES ('2017-01-17','2017-01-19',    3);
       INSERT INTO TT1 VALUES ('2017-01-18','2017-01-21',    4);
       INSERT INTO TT1 VALUES ('2017-01-22','2017-01-28',    5);
      
      SELECT MIN(CHCK)  AS CHK
      FROM (
              SELECT CASE WHEN DATEDIFF(dd, LAG(ENDDATE) OVER (ORDER BY DOW), STARTDATE) >1 THEN 0 ELSE 1 END AS CHCK
              FROM TT1
             ) A;
      

      输出 3:

      +-----+
      | CHK |
      +-----+
      | 0   |
      +-----+
      

      【讨论】:

        【解决方案3】:

        您可以使用铅来获得如下:

        select case when count(*) = sum(nextdt) then 'true' else 'false' end as Result
        from (
            select *, NextDt = case when dateadd(dd, 1, enddate) = lead(startdate, 1, dateadd(dd, 1, enddate)) over(order by startdate) then 1 else 0 end from #yourconsequentdate
        ) a
        

        【讨论】:

          【解决方案4】:

          您可以尝试按顺序加入范围并比较第一个范围的最后一天和第二个范围的第一天

          SELECT  iif(count(*)>0, 0, 1) as result 
          FROM    t prev 
          left outer join t next on (prev.Dow+1) = next.Dow 
          where
          DATEADD(d, 1, prev.EndDate) < next.StartDate
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-08-19
            • 2011-02-19
            • 2016-06-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-08-21
            • 1970-01-01
            相关资源
            最近更新 更多