繁体   English   中英

SQL 2012 比较多行的日期

[英]SQL 2012 Compare dates across several rows

我有一个问题,我需要比较几行的日期。 要求是数据需要按“区域/区域”组合进行分组,最低的“开始日期”和最高的“结束日期”除非前一个“结束日期”和下一个“开始日期”之间存在超过 1 天的间隔。

“StartDate”将始终是该月的第一天,而“EndDate”将始终是该月的最后一天。

给定一个简化的表格:

Region | Area |   StartDate   |   EndDate
-------|------|---------------|-------------
   A   |   1  |   01/01/2016  |  03/31/2016
   A   |   1  |   04/01/2016  |  05/31/2016
   A   |   1  |   07/01/2016  |  09/30/2016
   A   |   1  |   10/01/2016  |  01/31/2017
   A   |   1  |   02/01/2017  |  12/31/2017
   B   |   2  |   01/01/2016  |  04/30/2016
   B   |   2  |   05/01/2016  |  09/30/2016
   A   |   4  |   01/01/2016  |  05/31/2016
   A   |   4  |   06/01/2016  |  12/31/2016

我需要结果看起来像这样:

Region | Area |   StartDate  |  EndDate  
-------|------|--------------|-----------
   A   |   1  |  01/01/2016  |  05/31/2016
   A   |   1  |  07/01/2016  |  12/31/2017
   B   |   2  |  01/01/2016  |  09/30/2016
   A   |   4  |  01/01/2016  |  12/31/2016

我已经尝试过 GROUP BY 和 MIN 和 MAX 日期,但我似乎无法理解它的逻辑是正确的。

任何想法或建议将不胜感激。

这似乎是一个数据岛问题。 您可以利用 SQL Server 2012 中引入的窗口函数。使用LAG窗口函数,您可以确定您的最后一条记录结束日期时间与当前记录开始日期时间的差距是否大于一天。 接下来,您可以使用SUM OVER子句为每个数据岛生成分组 ID。

DECLARE @SourceData TABLE
(
     Region         NVARCHAR(10)
    ,Area           INT
    ,StartDate      DATETIME
    ,EndDate        DATETIME
);

INSERT INTO @SourceData
VALUES
('A', 1, '01/01/2016', '03/31/2016'),
('A', 1, '04/01/2016', '05/31/2016'),
('A', 1, '07/01/2016', '09/30/2016'),
('A', 1, '10/01/2016', '01/31/2017'),
('A', 1, '02/01/2017', '12/31/2017'),
('B', 2, '01/01/2016', '04/30/2016'),
('B', 2, '05/01/2016', '09/30/2016'),
('A', 4, '01/01/2016', '05/31/2016'),
('A', 4, '06/01/2016', '12/31/2016');

;WITH CTE_DataIslands  -- First CTE determine the start of each new data island
AS
(
    SELECT           Region
                    ,Area
                    ,StartDate
                    ,EndDate
                    ,(
                        CASE
                            WHEN DATEADD(DAY, 1, LAG(EndDate, 1) OVER  (PARTITION BY Region, Area ORDER BY StartDate ASC)) < (StartDate) THEN 1 -- If prev record's end date + 1 day  is not equal to current record's start date then it is the start of a new data island.
                            ELSE 0
                        END
                     ) AS [IsNewDataIsland]
    FROM            @SourceData 
)
, CTE_GenerateGroupingID
AS
(
    SELECT  Region
            ,Area
            ,StartDate
            ,EndDate
            ,SUM([IsNewDataIsland]) OVER (PARTITION BY Region, Area ORDER BY StartDate ASC ROWS UNBOUNDED PRECEDING) AS GroupingID  -- Create a running total of the IsNewDataIsland column this will create a grouping id we can now group on
    FROM    CTE_DataIslands
)
SELECT      Region  
            ,Area
            ,MIN(StartDate) AS StartDate
            ,MAX(EndDate) AS StartDate
FROM        CTE_GenerateGroupingID
GROUP BY    Region, Area, GroupingID

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM