在递归通用 table 表达式 (CTE) 的递归部分访问当前行(不是前一行)
Access current row (not previous row) in the recursive part of a recursive common table expression (CTE)
DB FIDDLE
示例代码
create table lifetable (
age int,
qx decimal(8, 6)
);
insert into
lifetable
values (18, 0.000066),
(19, 0.000130),
(20, 0.000244),
(21, 0.000256),
(22, 0.000289),
(23, 0.000301),
(24, 0.000377),
(25, 0.000406),
(26, 0.000431),
(27, 0.000442),
(28, 0.000456),
(29, 0.000476),
(30, 0.000566);
create table people (
age int,
name varchar(10)
);
insert into
people
values (18, 'George'),
(23, 'William'),
(27, 'Kate');
;with cte as (
select
name,
p.age,
qx,
cast(iif(p.age > 30, 0, 1) as decimal(10, 7)) as pxaa,
cast(iif(p.age > 30, 0, 1) as decimal(10, 7)) as tpxaa
from people as p
left join lifetable as lt
on p.age = lt.age
union all
select
name,
cte.age + 1,
lt.qx,
cast(pxaa * lt.qx as decimal(10, 7)), -- as pxaa
/****
** I need the current value of pxaa and the previous value of tpxaa to calculate
** the sebsequent values of tpxaa
**/
cast(lead(pxaa) over (partition by name order by cte.age asc) * tpxaa as decimal(10, 7)) -- as tpxaa
from cte
join lifetable as lt
on cte.age + 1 = lt.age
where cte.age < 30
) select * from cte order by name, age option (maxrecursion 0);
在这种特殊情况下,tpxaa 列在第一行中以 1 或 0 开始,从第二行开始,tpxaa 的值将使用其先前值(tpxaa 列中的上一行)和当前值进行计算pxaa 的(pxaa 列中的当前行)是另一列,其值也被计算。
除了使用递归 CTE,我不知道该怎么做。但是递归 CTE 只访问前一行。这很好,因为我可以得到前一行的 tpxaa,但我也得到了前一行的 pxaa,这是一种不受欢迎的行为。
我尝试在 pxaa 列中使用 OUTER APPLY,但是 SQL Server Management Studio (SSMS) 给我消息
The recurive member of the CTE has multiple recursive references
LAG 和 LEAD 将带来 NULL 值。可能是因为 pxaa 的值也在计算中
CROSS APPLY 会给我一个我不想要的笛卡尔积。
在Excel中,引用可以可视化:
如何计算一个列,其值取决于它自己的前一行和 SQL 服务器中另一个计算列的当前行?
免责声明
我其实不太擅长递归 CTE。我不认为这段代码对你来说是完全正确的,但我认为它可能会让你了解我认为你需要做什么:
;with cte as (
select
name,
p.age,
qx,
cast(iif(p.age > 30, 0, 1) as decimal(10, 7)) as pxaa,
cast(iif(p.age > 30, 0, 1) as decimal(10, 7)) as tpxaa,
cast (1 as decimal(10, 7)) as previoustpxaa -- I'm not sure what you want for the initial "previous" value of tpxaa since there is no such thing
from people as p
left join lifetable as lt
on p.age = lt.age
union all
select
name,
cte.age + 1,
lt.qx,
cast(pxaa * lt.qx as decimal(10, 7)) as pxaa,
cast(pxaa * previoustpxaa as decimal(10, 7)) as tpxaa, -- not sure if this should be pxaa * lt.qx * previoustpxaa or something else
tpxaa as previoustpxaa -- here is where you record the current as the previous
from cte
join lifetable as lt
on cte.age + 1 = lt.age
where cte.age < 30
) select * from cte order by name, age option (maxrecursion 0);
DB FIDDLE
示例代码
create table lifetable (
age int,
qx decimal(8, 6)
);
insert into
lifetable
values (18, 0.000066),
(19, 0.000130),
(20, 0.000244),
(21, 0.000256),
(22, 0.000289),
(23, 0.000301),
(24, 0.000377),
(25, 0.000406),
(26, 0.000431),
(27, 0.000442),
(28, 0.000456),
(29, 0.000476),
(30, 0.000566);
create table people (
age int,
name varchar(10)
);
insert into
people
values (18, 'George'),
(23, 'William'),
(27, 'Kate');
;with cte as (
select
name,
p.age,
qx,
cast(iif(p.age > 30, 0, 1) as decimal(10, 7)) as pxaa,
cast(iif(p.age > 30, 0, 1) as decimal(10, 7)) as tpxaa
from people as p
left join lifetable as lt
on p.age = lt.age
union all
select
name,
cte.age + 1,
lt.qx,
cast(pxaa * lt.qx as decimal(10, 7)), -- as pxaa
/****
** I need the current value of pxaa and the previous value of tpxaa to calculate
** the sebsequent values of tpxaa
**/
cast(lead(pxaa) over (partition by name order by cte.age asc) * tpxaa as decimal(10, 7)) -- as tpxaa
from cte
join lifetable as lt
on cte.age + 1 = lt.age
where cte.age < 30
) select * from cte order by name, age option (maxrecursion 0);
在这种特殊情况下,tpxaa 列在第一行中以 1 或 0 开始,从第二行开始,tpxaa 的值将使用其先前值(tpxaa 列中的上一行)和当前值进行计算pxaa 的(pxaa 列中的当前行)是另一列,其值也被计算。
除了使用递归 CTE,我不知道该怎么做。但是递归 CTE 只访问前一行。这很好,因为我可以得到前一行的 tpxaa,但我也得到了前一行的 pxaa,这是一种不受欢迎的行为。
我尝试在 pxaa 列中使用 OUTER APPLY,但是 SQL Server Management Studio (SSMS) 给我消息
The recurive member of the CTE has multiple recursive references
LAG 和 LEAD 将带来 NULL 值。可能是因为 pxaa 的值也在计算中
CROSS APPLY 会给我一个我不想要的笛卡尔积。
在Excel中,引用可以可视化:
如何计算一个列,其值取决于它自己的前一行和 SQL 服务器中另一个计算列的当前行?
免责声明
我其实不太擅长递归 CTE。我不认为这段代码对你来说是完全正确的,但我认为它可能会让你了解我认为你需要做什么:
;with cte as (
select
name,
p.age,
qx,
cast(iif(p.age > 30, 0, 1) as decimal(10, 7)) as pxaa,
cast(iif(p.age > 30, 0, 1) as decimal(10, 7)) as tpxaa,
cast (1 as decimal(10, 7)) as previoustpxaa -- I'm not sure what you want for the initial "previous" value of tpxaa since there is no such thing
from people as p
left join lifetable as lt
on p.age = lt.age
union all
select
name,
cte.age + 1,
lt.qx,
cast(pxaa * lt.qx as decimal(10, 7)) as pxaa,
cast(pxaa * previoustpxaa as decimal(10, 7)) as tpxaa, -- not sure if this should be pxaa * lt.qx * previoustpxaa or something else
tpxaa as previoustpxaa -- here is where you record the current as the previous
from cte
join lifetable as lt
on cte.age + 1 = lt.age
where cte.age < 30
) select * from cte order by name, age option (maxrecursion 0);