Sql 基于上一行中的计算值创建计算值

Sql 基于上一行中的计算值创建计算值,sql,sql-server,tsql,forecast,Sql,Sql Server,Tsql,Forecast,我正试图找到一种方法,将每月百分比变化应用于预测定价。我在excel中设置了我的问题,以使它更清楚一点。我正在使用SQL Server 2017 我们会说2018年9月1日之前的所有月份都是历史性的,2018年9月1日及以后的月份都是预测。我需要计算预测价格(在样本数据上用黄色阴影表示)使用 只是想澄清一下,我的数据中还不存在黄色阴影的价格。这就是我试图让我的查询计算的内容。因为这是每月的百分比变化,所以每一行取决于之前的行,并且超出了单个行数/分区解决方案,因为我们必须使用之前计算的价格。显

我正试图找到一种方法,将每月百分比变化应用于预测定价。我在excel中设置了我的问题,以使它更清楚一点。我正在使用SQL Server 2017

我们会说2018年9月1日之前的所有月份都是历史性的,2018年9月1日及以后的月份都是预测。我需要计算预测价格(在样本数据上用黄色阴影表示)使用


只是想澄清一下,我的数据中还不存在黄色阴影的价格。这就是我试图让我的查询计算的内容。因为这是每月的百分比变化,所以每一行取决于之前的行,并且超出了单个行数/分区解决方案,因为我们必须使用之前计算的价格。显然,excel中的简单顺序计算在这里要困难一些。知道如何在SQL中创建预测价格列吗?

在SQL Server中,您可以使用窗口功能和访问上一行/下一行的值。您需要通过在中指定来定义行的顺序。您可能需要包装select查询,该查询返回派生表或CTE中的prev/next值,然后从中选择并计算预测

with cte as (SELECT [Date], Price, LAG(Price, 1) over(order by [Date]) as PrevPrice from TABLE)
select [Date], Price, Price - PrevPrice as PriceChange from cte

您需要使用递归CTE。这是查看前一行计算值值的更简单方法之一:

DECLARE @t TABLE(Date DATE, ID VARCHAR(10), Price DECIMAL(10, 2), PctChange DECIMAL(10, 2));
INSERT INTO @t VALUES
('2018-01-01', 'ABC', 100,    NULL),
('2018-01-02', 'ABC', 150,   50.00),
('2018-01-03', 'ABC', 130,  -13.33),
('2018-01-04', 'ABC', 120,  -07.69),
('2018-01-05', 'ABC', 110,  -08.33),
('2018-01-06', 'ABC', 120,    9.09),
('2018-01-07', 'ABC', 120,    0.00),
('2018-01-08', 'ABC', 100,  -16.67),
('2018-01-09', 'ABC', NULL, -07.21),
('2018-01-10', 'ABC', NULL,   1.31),
('2018-01-11', 'ABC', NULL,   6.38),
('2018-01-12', 'ABC', NULL, -30.00),
('2019-01-01', 'ABC', NULL,  14.29),
('2019-01-02', 'ABC', NULL,   5.27);

WITH ncte AS (
    -- number the rows sequentially without gaps
    SELECT *, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Date) AS rn
    FROM @t
), rcte AS (
    -- find first row in each group
    SELECT *, Price AS ForecastedPrice
    FROM ncte AS base
    WHERE rn = 1
    UNION ALL
    -- find next row for each group from prev rows
    SELECT curr.*, CAST(prev.ForecastedPrice * (1 + curr.PctChange / 100) AS DECIMAL(10, 2))
    FROM ncte AS curr
    INNER JOIN rcte AS prev ON curr.ID = prev.ID AND curr.rn = prev.rn + 1
)
SELECT *
FROM rcte
ORDER BY ID, rn
结果:

| Date       | ID  |  Price | PctChange | rn | ForecastedPrice |
|------------|-----|--------|-----------|----|-----------------|
| 2018-01-01 | ABC | 100.00 |      NULL |  1 |          100.00 |
| 2018-01-02 | ABC | 150.00 |     50.00 |  2 |          150.00 |
| 2018-01-03 | ABC | 130.00 |    -13.33 |  3 |          130.01 |
| 2018-01-04 | ABC | 120.00 |     -7.69 |  4 |          120.01 |
| 2018-01-05 | ABC | 110.00 |     -8.33 |  5 |          110.01 |
| 2018-01-06 | ABC | 120.00 |      9.09 |  6 |          120.01 |
| 2018-01-07 | ABC | 120.00 |      0.00 |  7 |          120.01 |
| 2018-01-08 | ABC | 100.00 |    -16.67 |  8 |          100.00 |
| 2018-01-09 | ABC |   NULL |     -7.21 |  9 |           92.79 |
| 2018-01-10 | ABC |   NULL |      1.31 | 10 |           94.01 |
| 2018-01-11 | ABC |   NULL |      6.38 | 11 |          100.01 |
| 2018-01-12 | ABC |   NULL |    -30.00 | 12 |           70.01 |
| 2019-01-01 | ABC |   NULL |     14.29 | 13 |           80.01 |
| 2019-01-02 | ABC |   NULL |      5.27 | 14 |           84.23 |

第一个150来自哪里?150=50%*100+100。价格从1/1/18开始,加上50%的价格上涨。我相信你需要用递归来解决它。滞后/求和在这里没有帮助。太棒了。我稍后会试试这个。我没有在示例数据中添加的一件事是在同一时间跨度内添加多个ID。我猜这可能是over语句中的某种分区,或者只是一个groupby。如果我不能找出那个部分,我会向你汇报。如果我正确地理解了你的观点,你需要在over子句
LAG(Price,1)over(partition by element id order by[Date])中添加“partition by”,作为amelement类型的prevPrice
是的,这很有效。第一次使用递归。然而,如果我们将此应用于数百万行,我认为处理速度会非常慢,对吗?是的,它是迭代的,难以优化,或者可能不可能优化。除了速度慢,我还担心递归限制。。。SQL server最多在32768次迭代后停止。
| Date       | ID  |  Price | PctChange | rn | ForecastedPrice |
|------------|-----|--------|-----------|----|-----------------|
| 2018-01-01 | ABC | 100.00 |      NULL |  1 |          100.00 |
| 2018-01-02 | ABC | 150.00 |     50.00 |  2 |          150.00 |
| 2018-01-03 | ABC | 130.00 |    -13.33 |  3 |          130.01 |
| 2018-01-04 | ABC | 120.00 |     -7.69 |  4 |          120.01 |
| 2018-01-05 | ABC | 110.00 |     -8.33 |  5 |          110.01 |
| 2018-01-06 | ABC | 120.00 |      9.09 |  6 |          120.01 |
| 2018-01-07 | ABC | 120.00 |      0.00 |  7 |          120.01 |
| 2018-01-08 | ABC | 100.00 |    -16.67 |  8 |          100.00 |
| 2018-01-09 | ABC |   NULL |     -7.21 |  9 |           92.79 |
| 2018-01-10 | ABC |   NULL |      1.31 | 10 |           94.01 |
| 2018-01-11 | ABC |   NULL |      6.38 | 11 |          100.01 |
| 2018-01-12 | ABC |   NULL |    -30.00 | 12 |           70.01 |
| 2019-01-01 | ABC |   NULL |     14.29 | 13 |           80.01 |
| 2019-01-02 | ABC |   NULL |      5.27 | 14 |           84.23 |