【问题标题】:Merging and Restructuring Date Ranges (TSQL)合并和重组日期范围 (SQL)
【发布时间】:2014-10-13 22:36:52
【问题描述】:

我有三张表:每种类型的服务一张。每个表格都列出了客户在不同日期期间对该特定服务的价格:

TABLE: SERVICE_A
 | StartDate    | EndDate      | Price  |
 ----------------------------------------
 | 01/01/2013   | 16/04/2013   | 30     |
 | 17/04/2013   | 20/09/2013   | 33     |
 | 21/09/2013   | 31/12/2013   | 34     |


TABLE: SERVICE_B
 | StartDate    | EndDate      | Price  |
 ----------------------------------------
 | 01/01/2013   | 30/06/2013   | 47     |
 | 01/07/2013   | 31/12/2013   | 49     |


TABLE: SERVICE_C
 | StartDate    | EndDate      | Price  |
 ----------------------------------------
 | 01/01/2013   | 03/03/2013   | 96     |
 | 04/03/2013   | 31/12/2013   | 101    |

我正在尝试创建一个表格来合并这些数据并对其进行重组以显示适当日期范围内所有三种服务的价格:

RESULTS
 | StartDate    | EndDate      | PriceA | PriceB | PriceC |
 ----------------------------------------------------------
 | 01/01/2013   | 03/03/2013   | 30     | 47     | 96     |
 | 04/03/2013   | 16/04/2013   | 30     | 47     | 101    |
 | 17/04/2013   | 30/06/2013   | 33     | 47     | 101    |
 | 01/07/2013   | 20/09/2013   | 33     | 49     | 101    |
 | 21/09/2013   | 31/12/2013   | 34     | 49     | 101    |

对于此查询的任何帮助将不胜感激! (我使用的是 SQL Server 2008 R2)。

【问题讨论】:

    标签: sql tsql date merge sql-server-2008-r2


    【解决方案1】:

    这是一个可怕的解决方案,但它不使用光标:D

    首先,我需要将您的数据放入表变量中,以便进行测试。

    DECLARE @ServiceA TABLE (
        StartDate DATE,
        EndDate DATE,
        Price INT);
    INSERT INTO @ServiceA VALUES ('2013-01-01', '2013-04-16', 30);
    INSERT INTO @ServiceA VALUES ('2013-04-17', '2013-09-20', 33);
    INSERT INTO @ServiceA VALUES ('2013-09-21', '2013-12-31', 34);
    DECLARE @ServiceB TABLE (
        StartDate DATE,
        EndDate DATE,
        Price INT);
    INSERT INTO @ServiceB VALUES ('2013-01-01', '2013-06-30', 47);
    INSERT INTO @ServiceB VALUES ('2013-07-01', '2013-12-31', 49);
    DECLARE @ServiceC TABLE (
        StartDate DATE,
        EndDate DATE,
        Price INT);
    INSERT INTO @ServiceC VALUES ('2013-01-01', '2013-03-03', 96);
    INSERT INTO @ServiceC VALUES ('2013-03-04', '2013-12-31', 101);
    

    现在我可以编写一个可怕的查询,以您想要的方式提取数据:

    WITH DistinctDates AS (
        SELECT
            StartDate,
            EndDate
        FROM
            @ServiceA
        UNION
        SELECT
            StartDate,
            EndDate
        FROM
            @ServiceB
        UNION
        SELECT
            StartDate,
            EndDate
        FROM
            @ServiceC),
    OrderedDates AS (
        SELECT
            ROW_NUMBER() OVER (PARTITION BY StartDate ORDER BY EndDate) AS StartNumber,
            ROW_NUMBER() OVER (PARTITION BY EndDate ORDER BY StartDate DESC) AS EndNumber,
            *
        FROM
            DistinctDates),
    FixOverlaps AS (
        SELECT
            CASE WHEN o2.StartNumber IS NULL THEN o1.StartDate ELSE DATEADD(DAY, 1, o2.EndDate) END AS StartDate,
            CASE WHEN o3.EndNumber IS NULL THEN o1.EndDate ELSE DATEADD(DAY, -1, o3.StartDate) END AS EndDate
        FROM
            OrderedDates o1
            LEFT JOIN OrderedDates o2 ON o2.StartDate = o1.StartDate AND o2.StartNumber = o1.StartNumber - 1
            LEFT JOIN OrderedDates o3 ON o3.EndDate = o1.EndDate AND o3.EndNumber = o1.EndNumber - 1),
    MergeDates AS (
        SELECT
            StartDate,
            EndDate,
            ROW_NUMBER() OVER (PARTITION BY StartDate ORDER BY EndDate) AS MergeNumber
        FROM
            FixOverlaps)
    SELECT 
        md.StartDate,
        md.EndDate,
        a.Price,
        b.Price,
        c.Price
    FROM 
        MergeDates md
        LEFT JOIN @ServiceA a ON a.StartDate <= md.EndDate AND a.EndDate >= md.StartDate
        LEFT JOIN @ServiceB b ON b.StartDate <= md.EndDate AND b.EndDate >= md.StartDate
        LEFT JOIN @ServiceC c ON c.StartDate <= md.EndDate AND c.EndDate >= md.StartDate
    WHERE 
        md.MergeNumber = 1;
    

    ...结果是:

    StartDate   EndDate     PriceA  PriceB  PriceC
    2013-01-01  2013-03-03  30      47      96
    2013-03-04  2013-04-16  30      47      101
    2013-04-17  2013-06-30  33      47      101
    2013-07-01  2013-09-20  33      49      101
    2013-09-21  2013-12-31  34      49      101
    

    【讨论】:

    • 非常感谢您提供此解决方案。它可能看起来很可怕,但效果很好! :)
    【解决方案2】:

    应该这样做。我正在考虑在开始日期您拥有所有三个价格:

    CREATE TABLE #Services (
        StartDate DATETIME
        , EndDate DATETIME
        , PriceA INT
        , PriceB INT
        , PriceC INt
    )
    
    DECLARE @startDt DateTime, @endDt DateTime, @Price Int, @Service Char(1)
    DECLARE @PriceA Int, @PriceB Int, @PriceC Int, @previousStartDate DateTime, @finalEndDate DateTime
    SET @previousStartDate = '20130101'
    
    DECLARE cursorDatePrices CURSOR FOR
    SELECT StartDate, EndDate, Price, 'A' as Service
    FROM #SA
    UNION ALL
    SELECT StartDate, EndDate, Price, 'B' as Service
    FROM #SB
    UNION ALL
    SELECT StartDate, EndDate, Price, 'C' as Service
    FROM #SC
    ORDER BY StartDate
    
    OPEN cursorDatePrices
    
    FETCH NEXT FROM cursorDatePrices
    INTO @startDt, @endDt, @Price, @Service
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
        --only insert after having the three prices
        IF (@PriceA IS NOT NULL AND @PriceB IS NOT NULL AND @PriceC IS NOT NULL)
        BEGIN
            INSERT INTO #Services VALUES (@previousStartDate, DATEADD(dd, -1, @startDt), @PriceA, @PriceB, @PriceC)
            SET @previousStartDate = @startDt
        END
    
        IF (@Service = 'A') SET @PriceA = @Price
        ELSE IF (@Service = 'B') SET @PriceB = @Price
        ELSE IF (@Service = 'C') SET @PriceC = @Price
    
        FETCH NEXT FROM cursorDatePrices
        INTO @startDt, @endDt, @Price, @Service
    END
    
    CLOSE cursorDatePrices
    DEALLOCATE cursorDatePrices
    
    INSERT INTO #Services VALUES (@previousStartDate, @endDt, @PriceA, @PriceB, @PriceC)
    SELECT * from #Services
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-22
      • 2011-06-25
      相关资源
      最近更新 更多