【问题标题】:SQL Server Logic for Detecting Gaps in Dates Sequence用于检测日期序列间隙的 SQL Server 逻辑
【发布时间】:2015-10-28 06:55:11
【问题描述】:

我有下表:

     Plan     Start Date     End Date     Order    
    ------------------------------------------
      1    1st Jan, 2014  31st Jan, 2014   1
      1    1st Feb, 2014  24th Feb, 2014   2
      1   25th Feb, 2014  30th Jun, 2014   3
      1    7th Jul, 2014  28th Aug, 2014   4
      1    1st Sep, 2014  30th Sep, 2014   5
      1    1st Oct, 2014  31st Dec, 2014   6

从上面的数据可以看出,对于计划 1,订单 1,2,3 是连续的,那么我们有一个缺口,然后是订单 4,然后又是一个缺口,然后是订单 5,6 是连续的。对于计划 1,我想将覆盖范围捆绑如下:(1,2,3),(4),(5,6),预期结果集应如下所示:

     Plan     Start Date     End Date         
    -------------------------------------
      1    1st Jan, 2014  30th Jun, 2014 
      1    7th Jul, 2014  28th Aug, 2014 
      1    1st Sep, 2014  31st Dec, 2014

我使用了一个基本的 while 循环迭代逻辑来实现我想要的输出。但是,当有大量记录(比如 100 万条)时,while 循环逻辑的性能会受到很大影响(因为它是逐行操作)。我尝试提出一种基于递归 CTE 的方法,但无法获得预期的结果。在这种情况下,任何可以使用批处理逻辑的输入都将非常有用。

【问题讨论】:

    标签: sql-server-2008 date while-loop sequence common-table-expression


    【解决方案1】:

    WHERE 中的子查询过滤掉连续的行。 SELECT 中的子查询将找到日期范围结束。

    数据:

    CREATE TABLE #tab([Plan] INT, StartDate DATE, EndDate DATE, [Order] INT )
    
    INSERT INTO #tab VALUES
    (1, '2014-01-01', '2014-01-31', 1),(1, '2014-02-01', '2014-02-24', 2),
    (1, '2014-02-25', '2014-06-30', 3),(1, '2014-07-07', '2014-08-28', 4),
    (1, '2014-09-01', '2014-09-30', 5),(1, '2014-10-01', '2014-12-31', 6);
    

    查询:

    SELECT [Plan],D.StartDate, 
       [EndDate] = (SELECT MIN(E.EndDate)
                    FROM #tab E
                    WHERE E.EndDate >= D.EndDate
                     AND E.[Plan] = D.[Plan]
                     AND NOT EXISTS (SELECT 1
                                     FROM #tab E2
                                     WHERE DATEADD(d,1,E.StartDate) < E2.StartDate
                                       AND DATEADD(d,1,E.EndDate) >= E2.StartDate
                                       AND E.[Plan] = E2.[Plan]))
    FROM #tab D
    WHERE NOT EXISTS (SELECT 1
                      FROM #tab D2
                      WHERE D.StartDate <= DATEADD(d, 1,D2.EndDate)
                        AND D.EndDate > D2.EndDate
                        AND D.[Plan] = D2.[Plan])
    ORDER BY [Plan], StartDate;
    

    LiveDemo

    输出:

    ╔══════╦═════════════════════╦═════════════════════╗
    ║ Plan ║      StartDate      ║       EndDate       ║
    ╠══════╬═════════════════════╬═════════════════════╣
    ║    1 ║ 2014-01-01 00:00:00 ║ 2014-06-30 00:00:00 ║
    ║    1 ║ 2014-07-07 00:00:00 ║ 2014-08-28 00:00:00 ║
    ║    1 ║ 2014-09-01 00:00:00 ║ 2014-12-31 00:00:00 ║
    ╚══════╩═════════════════════╩═════════════════════╝
    

    【讨论】:

      【解决方案2】:

      查看另一个查询

          declare @tab table ([Plan] INT, StartDate DATE, EndDate DATE, [Order] INT )      
          INSERT INTO @tab VALUES
          (1, '2014-01-01', '2014-01-31', 1),(1, '2014-02-01', '2014-02-24', 2),
          (1, '2014-02-25', '2014-06-30', 3),(1, '2014-07-07', '2014-08-28', 4),
          (1, '2014-09-01', '2014-09-30', 5),(1, '2014-10-01', '2014-12-31', 6)
      
          select [plan], Max(case when ro in (1,4,5) then startDate end) st,
          Max(case when ro in (3,4,0) then endDate end) et from (
          select *, ([order]-1) / 6 as grp,
          [order]%6 as ro, case when ([order] % 6)<4 and ([order] % 6)!=0 then 1
       when ([order] % 6)=4 then 2 else 3 end as subgrp
          from @tab) t group by [plan],grp,subgrp
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-01-27
        • 2012-03-03
        • 2020-04-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多