2016-10-12 8 views
1

私はいくつかの行の日付を比較する必要がある問題があります。要件は、前回の 'EndDate'と次の 'StartDate'の間に1日以上のギャップがない限り、データを 'StartDate'と最高 'EndDate'が最も低い 'Region/Area'の組み合わせでグループ化する必要があります。SQL 2012いくつかの行の日付を比較する

「StartDate」は常に最初の月で、「EndDate」は常にその月の最終日になります。私はMINとのGROUP BYを試してみましたし、MAXは、日付が、私はように見えることはできません

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 

:私はこのような何かを見て、結果を必要

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 

は、次のような単純化されたテーブルを考えますそれの論理を正しいものにしてください。

ご意見やご提案をいただければ幸いです。

答えて

1

これはデータアイランドの問題のようです。 SQL Server 2012で導入されたウィンドウ関数を使用することができます。ウィンドウ機能を使用すると、最後のレコードの終了日時に現在のレコードの開始日時との1日を超えるギャップがあるかどうかを判断できます。次に、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 
+0

おかげで、私はちょうど@JeffMartinez心配一緒 –

+0

をそれらを取得しないように見えることができなかった部分があったが、あまり、それがために働い嬉しいあなたは –

+0

一つ質問をフォローアップ - 第三日付列があった場合には、たとえば'ChangeDate'、各グループごとにMAX値が必要です。どのようにそれを含める?私が試してみると結果が増え続けます –