如何从 SQL 中的每日记录表生成日期范围

问题描述 投票:0回答:1

我正在尝试根据以下数据集创建价格历史记录。我有一个包含价格的每一天的记录,可以在不同时期重复。请参阅下面的输入:

价格 日期
20 2023-01-01
20 2023-01-02
19 2023-01-03
19 2023-01-04
20 2023-01-05
20 2023-01-06

我想总结成这样的价格历史表:

价格 开始日期 结束日期
20 2023-01-01 2023-01-02
19 2023-01-03 2023-01-04
20 2023-01-05 2023-01-06

任何人都可以指出我正确的方向吗?我已经能够创建范围,但是被多个范围出现相同价格的可能性绊倒了,所以这搞乱了分组。

sql sql-server gaps-and-islands
1个回答
0
投票

我获取了您的示例数据并将其转换为可重现的 DML/DDL,这对解决此类问题非常有帮助。我添加了一个 ProductID 列和一些额外的数据行来演示如何使用多个 ID 来完成此操作。我使用表变量是因为要清理的东西更少,但这只是个人喜好。

DECLARE @PriceHistory TABLE (ProductID BIGINT, Price DECIMAL (10,2), Date DATE)
INSERT INTO @PriceHistory (ProductID, Price, Date) VALUES
(1, 20, '2023-01-01'), (1, 20, '2023-01-02'), (1, 20, '2023-01-03'), (1, 19, '2023-01-04'),
(1, 20, '2023-01-05'), (1, 20, '2023-01-06'), (1, 20, '2023-01-07'), (1, 20, '2023-01-08'),
(2, 30, '2023-01-01'), (2, 15, '2023-01-02'), (2, 15, '2023-01-03'), (2, 19, '2023-01-04'),
(2, 19, '2023-01-05'), (2, 20, '2023-01-06'), (2, 20, '2023-01-07'), (2, 20, '2023-01-08');

使用它,我们可以使用递归公用表表达式进行查询以获得您要查找的结果。为了分隔范围,我使用了一个 LAG 窗口函数来标记这一行是否与前一行属于同一范围。

;WITH base AS (
SELECT ProductID, Price, Date, CASE WHEN LAG(Price,1) OVER (PARTITION BY ProductID ORDER BY Date) = Price THEN 1 ELSE 0 END AS InRange
  FROM @PriceHistory
), Ranges AS (
SELECT ProductID, Price, Date AS StartDate, Date AS EndDate
  FROM base 
 WHERE InRange = 0
UNION ALL
SELECT a.ProductID, a.Price, a.StartDate, r.Date AS EndDate
  FROM Ranges a
    INNER JOIN Base r
      ON a.ProductID = r.ProductID
      AND a.EndDate = DATEADD(DAY,-1,r.Date)
      AND a.Price = r.Price
)

SELECT ProductID, Price, StartDate, MAX(EndDate) AS EndDate, DATEDIFF(DAY,StartDate, MAX(EndDate))+1 AS Duration
  FROM Ranges
 GROUP BY ProductID, Price, StartDate
 ORDER BY Ranges.ProductID, Ranges.StartDate;
产品编号 价格 开始日期 结束日期 持续时间
1 20.00 2023-01-01 2023-01-03 3
1 19.00 2023-01-04 2023-01-04 1
1 20.00 2023-01-05 2023-01-08 4
2 30.00 2023-01-01 2023-01-01 1
2 15.00 2023-01-02 2023-01-03 2
2 19.00 2023-01-04 2023-01-05 2
2 20.00 2023-01-06 2023-01-08 3
© www.soinside.com 2019 - 2024. All rights reserved.