Joining together consecutive date validity intervals

后端 未结 4 2055
予麋鹿
予麋鹿 2021-01-14 02:59

I have a series of records containing some information (product type) with temporal validity.

I would like to meld together adjacent validity intervals, provided tha

4条回答
  •  深忆病人
    2021-01-14 03:04

    This is a pretty complicated set of steps, but it's the way that I solved a similar problem:

    -- Sample Data
    CREATE TABLE AdjacentValidity 
      (
    RowID INT IDENTITY(1,1) NOT NULL,
    Product VARCHAR(1) NOT NULL,
    Start_Date DATETIME NOT NULL,
    End_Date DATETIME NOT NULL
      )
    
    INSERT INTO AdjacentValidity (Product, Start_Date, End_Date)
    
    SELECT 'A', '7/1/2013', '7/31/2013' UNION
    SELECT 'A', '8/1/2013', '8/31/2013' UNION
    SELECT 'A', '9/1/2013', '9/30/2013' UNION
    SELECT 'B', '10/1/2013', '10/31/2013' UNION
    SELECT 'B', '11/1/2013', '11/30/2013' UNION
    SELECT 'A', '12/1/2013', '12/31/2013' UNION
    SELECT 'A', '1/1/2014', '1/31/2014' UNION
    SELECT 'A', '2/1/2014', '2/28/2014' UNION
    SELECT 'A', '3/1/2014', '3/31/2014'
    
    
    -- Modify the sample data to include necessary tags
    CREATE TABLE #RawData
      (
        RawData_ID INT IDENTITY(1,1) NOT NULL,
        Product VARCHAR(1) NOT NULL,
        Start_Date DATETIME NOT NULL,
        End_Date DATETIME NOT NULL,
        isFirstOccurrence BIT NULL,
        isLastOccurrence BIT NULL,
        isFirstInstance BIT NULL,
        isLastInstance BIT NULL
      )
    
    -- Load and flag first occurrences of a natural key
    INSERT INTO #RawData
      (
        Product,
        Start_Date,
        End_Date,
        isFirstInstance
      )
    SELECT 
        Product,
        Start_Date,
        End_Date,
        CASE WHEN ROW_NUMBER() OVER
          (
            --PARTITION BY 
            ORDER BY Start_date
          ) = 1 THEN 1 ELSE 0 END AS isFirstOccurrence
    FROM AdjacentValidity
    
    -- update to flag the last sequential instance of a particalar data set, and the last     occurrence of a natural key
    UPDATE a
    SET 
        a.isLastInstance = 
         CASE 
          WHEN 
            a.Product <> b.Product OR 
            DATEADD(m, 1, a.Start_Date) <> b.Start_Date  OR
            b.RawData_ID IS NULL
          THEN 1 
          ELSE 0 
         END,
        a.isLastOccurrence = 
         CASE
          WHEN 
            b.RawData_ID IS NULL
          THEN 1 
          ELSE 0 
         END 
    FROM 
        #RawData a
         LEFT JOIN
        #RawData b ON 
            b.RawData_ID = a.RawData_ID + 1 --AND 
            --b. = a.
    
    --  flag first sequential instance of a particular data set
    UPDATE b
    SET 
        b.isFirstInstance = 
         CASE 
          WHEN 
            a.isLastInstance = 1
          THEN 1 
          ELSE 0 
         END 
    FROM 
        #RawData a
         LEFT JOIN
        #RawData b ON 
            b.RawData_ID = a.RawData_ID + 1 --AND 
            --b. = a.
    
    
    -- reduce the records to only those that are the first or last occurrence of a     particular data set
    CREATE TABLE #UniqueData 
      (
        [UniqueData_ID] [int] IDENTITY(1,1) NOT NULL,
        Start_Date DATETIME NOT NULL,
        End_Date DATETIME NOT NULL,
        Product VARCHAR(1) NULL,
        isFirstOccurrence BIT NULL,
        isLastOccurrence BIT NULL,
        isFirstInstance BIT NULL,
        isLastInstance BIT NULL
      ) 
    
    INSERT INTO #UniqueData
      (
        Start_Date,
        End_Date,
        Product,
        isFirstOccurrence,
        isLastOccurrence,
        isFirstInstance,
        isLastInstance
      )
    
    SELECT 
        Start_Date,
        End_Date,
        Product,
        isFirstOccurrence,
        isLastOccurrence,
        isFirstInstance,
        isLastInstance
    FROM 
        #RawData 
    WHERE 
        isFirstOccurrence = 1 OR
        isFirstInstance = 1 OR
        isLastInstance = 1
    ORDER BY RawData_ID, Start_Date
    
    
    
    
    -- combine the first and last occurrences in any given sequence into a single row
    SELECT 
        a.Start_Date,
        ISNULL(b.Start_Date, a.End_Date) End_Date,
        a.Product
    FROM 
        #UniqueData a 
         LEFT JOIN
        #UniqueData b ON 
            b.UniqueData_ID = a.UniqueData_ID + 1 AND
            --b. = a. AND
            a.isLastInstance <> 1
    WHERE a.isFirstInstance = 1 or a.isFirstOccurrence = 1
    ORDER BY a.UniqueData_ID
    
    
    
    -- clean up
    /*
    DROP TABLE AdjacentValidity
    DROP TABLE #RawData
    DROP TABLE #UniqueData
    */
    

提交回复
热议问题