检测到重叠日期时间和总和

时间:2017-09-15 11:41:43

标签: sql-server overlapping

我正在尝试构建可以检查重叠日期时间的查询,我需要逐个chceck记录。这是我的表:

ID_p    id_k    start                   end
1568    1   2017-09-11 13:32:59.000 2017-09-11 13:47:19.000
1568    2   2017-09-11 15:20:51.000 2017-09-11 15:26:28.000
1568    3   2017-09-11 15:26:28.000 2017-09-11 15:26:29.000
1568    4   2017-09-11 15:26:29.000 2017-09-11 15:26:40.000
1568    5   2017-09-11 15:26:40.000 2017-09-11 15:26:56.000
1568    6   2017-09-11 15:26:56.000 2017-09-11 15:38:24.000
1568    7   2017-09-11 18:13:24.000 2017-09-11 18:26:56.000

我想做的是: 找到重叠,chceck如果第一行来自kolumn'end'=“start”在行nyber 2.当我知道哪一个只想总结它时,我期望的是:

ID_p    id_k    start   end
1568    1   2017-09-11 13:32:59.000 2017-09-11 13:47:19.000
1568    2   2017-09-11 15:20:51.000 2017-09-11 15:38:24.000
1568    3   2017-09-11 18:13:24.000 2017-09-11 18:26:56.000

我该怎么做?你能解释一下吗?

3 个答案:

答案 0 :(得分:1)

您可以使用Lag和Lead来获取下一行并预览该行的值:

SELECT
LAG(start) OVER (ORDER BY ID_p) prev_start, start, LEAD(start) OVER (ORDER BY ID_p) next_start,
LAG(end) OVER (ORDER BY ID_p) prev_end, end, LEAD(end) OVER (ORDER BY ID_p) next_end
FROM your_table

并且您可以在其中比较prev,current和next值。也许你需要通过另一个专栏来订购,比如start。

答案 1 :(得分:0)

尝试下面的代码:让我知道它是否适用于您的所有记录:

  --sample data
  WITH ABC
  AS
  (
  SELECT '1568' as ID_p,1 as id_k,'2017-09-11 13:32:59.000' as Start, '2017-09-11 13:47:19.000' as [End]
  UNION 
   SELECT '1568' as ID_p,2 as id_k,'2017-09-11 15:20:51.000' as Start, '2017-09-11 15:26:28.000' as [End]
   UNION
  Select  '1568' as ID_p,3 as id_k,'2017-09-11 15:26:28.000' as Start, '2017-09-11 15:26:29.000'
   UNION
  Select  '1568' as ID_p,4 as id_k,'2017-09-11 15:26:29.000' as Start, '2017-09-11 15:26:40.000'
   UNION
  Select  '1568' as ID_p,5 as id_k,'2017-09-11 15:26:40.000' as Start, '2017-09-11 15:26:56.000'
   UNION
  Select  '1568' as ID_p,6 as id_k,'2017-09-11 15:26:56.000' as Start, '2017-09-11 15:38:24.000'
   UNION
  Select  '1568' as ID_p,7 as id_k,'2017-09-11 18:13:24.000' as Start, '2017-09-11 18:26:56.000'

  )
   --actual query:
    SELECT ID_p, ROW_NUMBER()OVER(ORDER BY ID_p)as id_k,MIN(start)as start,MAX([end]) as [End]
  FROM
  (
  SELECT ID_p, id_k, start, [end], lag([end])OVER(PARTITION BY DATEPART(hour,start) ORDER BY [end]) as new_end
  FROM ABC
  ) as A
  WHERE DATEPART(hour,start) = DATEPART(hour,[end])
  GROUP BY DATEPART(hour,start),ID_p



    --output:
      ID_p  id_k    start                   End
      1568  1   2017-09-11 13:32:59.000 2017-09-11 13:47:19.000
      1568  2   2017-09-11 15:20:51.000 2017-09-11 15:38:24.000
      1568  3   2017-09-11 18:13:24.000 2017-09-11 18:26:56.000

简短说明:使用Lag函数来聚合start中具有相同小时值的行,外部WHERE子句限制end的小时应该与start相同,然后其余代码不会对每个集合进行分组,并使用ROW_NUMBER作为增量列。

答案 2 :(得分:0)

这是另一个可以在SQL Server 2012中使用的解决方案。后来...

IF OBJECT_ID('tempdb..#TestData', 'U') IS NOT NULL 
DROP TABLE #TestData;

CREATE TABLE #TestData (
    ID_p INT NOT NULL,
    id_k INT NOT NULL,
    BegDT DATETIME NOT NULL,
    EndDT DATETIME NOT NULL,
    PRIMARY KEY CLUSTERED (ID_p, id_k) 
    );
INSERT #TestData (ID_p, id_k, BegDT, EndDT) VALUES
    (1568, 1, '2017-09-11 13:32:59.000', '2017-09-11 13:47:19.000'),
    (1568, 2, '2017-09-11 15:20:51.000', '2017-09-11 15:26:28.000'),
    (1568, 3, '2017-09-11 15:26:28.000', '2017-09-11 15:26:29.000'),
    (1568, 4, '2017-09-11 15:26:29.000', '2017-09-11 15:26:40.000'),
    (1568, 5, '2017-09-11 15:26:40.000', '2017-09-11 15:26:56.000'),
    (1568, 6, '2017-09-11 15:26:56.000', '2017-09-11 15:38:24.000'),
    (1568, 7, '2017-09-11 18:13:24.000', '2017-09-11 18:26:56.000');

--==================================================================

WITH 
    cte_FindGroupEdge AS (
        SELECT 
            td.ID_p, td.id_k, td.BegDT, td.EndDT,
            GroupEdge = CASE WHEN td.BegDT = LAG(td.EndDT) OVER (PARTITION BY td.ID_p ORDER BY td.id_k) THEN NULL ELSE td.id_k END
        FROM
            #TestData td
        ),
    cte_GroupFill AS (
        SELECT 
            fge.ID_p, fge.id_k, fge.BegDT, fge.EndDT, 
            GroupFill = MAX(fge.GroupEdge) OVER (PARTITION BY fge.ID_p ORDER BY fge.id_k ROWS UNBOUNDED PRECEDING)
        FROM
            cte_FindGroupEdge fge
        )
SELECT 
    gf.ID_p,
    id_k = ROW_NUMBER() OVER (PARTITION BY gf.ID_p ORDER BY  MIN(gf.BegDT)),
    BegDT = MIN(gf.BegDT),
    EndDT = MAX(gf.EndDT)
FROM
    cte_GroupFill gf
GROUP BY
    gf.ID_p,
    gf.GroupFill;

结果...

ID_p        id_k                 BegDT                   EndDT
----------- -------------------- ----------------------- -----------------------
1568        1                    2017-09-11 13:32:59.000 2017-09-11 13:47:19.000
1568        2                    2017-09-11 15:20:51.000 2017-09-11 15:38:24.000
1568        3                    2017-09-11 18:13:24.000 2017-09-11 18:26:56.000