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
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
如果有负数 multiplier
s,这将失败。
如果您想要一个 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
我有一个 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
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
如果有负数 multiplier
s,这将失败。
如果您想要一个 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