T-SQL 两列顺序更新

T-SQL sequential updating with two columns

我有一个 table 创建者:

CREATE TABLE table1 
(
    id INT,
    multiplier INT,
    col1 DECIMAL(10,5)
)

INSERT INTO table1 
VALUES (1, 2, 1.53), (2, 3, NULL), (3, 2, NULL),
       (4, 2, NULL), (5, 3, NULL), (6, 1, NULL)

这导致:

id  multiplier  col1
-----------------------
1   2           1.53000
2   3           NULL
3   2           NULL
4   2           NULL
5   3           NULL
6   1           NULL

我想添加一个定义为 multiplier * col1 的列 col2,但是 col1 的下一个值随后更新为采用 col2 的先前计算值.

结果 table 应如下所示:

id  multiplier  col1        col2
---------------------------------------
1       2         1.53000     3.06000
2       3         3.06000     9.18000
3       2         9.18000    18.36000
4       2        18.36000    36.72000
5       3        36.72000   110.16000
6       1       110.16000   110.16000

这可以使用 T-SQL 吗?我尝试了一些不同的事情,例如将 id 加入 id - 1 并尝试使用 UPDATE 进行顺序更新并设置变量,但我无法让它工作。

递归 CTE 可能是最好的方法。假设您的 id 没有间隙:

with cte as (
      select id, multiplier, convert(float, col1) as col1, convert(float, col1 * multiplier) as col2
      from table1
      where id = 1
      union all
      select t1.id, t1.multiplier, cte.col2 as col1, cte.col2 * t1.multiplier
      from cte join
           table1 t1
           on t1.id = cte.id + 1
     )
select *
from cte;

Here 是一个 db<>fiddle.

注意,我把目标类型转为float,方便这种操作。如果您愿意,可以转换回 decimal

基本上,这需要一个 aggregate/window 函数来计算列值的乘积。但是 SQL 中不存在这样的设置函数。我们可以用算术来解决这个问题:

select
    id,
    multiplier,
    coalesce(min(col1) over() * exp(sum(log(multiplier)) over(order by id rows between unbounded preceding and 1 preceding)), col1) col1,
    min(col1) over() * exp(sum(log(multiplier)) over(order by id)) col2
from table1

Demo on DB Fiddle:

id | multiplier |   col1 |   col2
-: | ---------: | -----: | -----:
 1 |          2 |   1.53 |   3.06
 2 |          3 |   3.06 |   9.18
 3 |          2 |   9.18 |  18.36
 4 |          2 |  18.36 |  36.72
 5 |          3 |  36.72 | 110.16
 6 |          1 | 110.16 | 110.16

如果有负数 multipliers,这将失败。

如果您想要一个 update 语句:

with cte as (
    select col1, col2,
        coalesce(min(col1) over() * exp(sum(log(multiplier)) over(order by id rows between unbounded preceding and 1 preceding)), col1) col1_new,
        min(col1) over() * exp(sum(log(multiplier)) over(order by id)) col2_new
    from table1
)
update cte set col1 = col1_new, col2 = col2_new