如何在 CTE 中对 SQL 服务器中从当前行到最后一行的列的值求和
How to sum the values of a column in SQL Server from the current row to the last within a CTE
SQL FIDDLE
我尝试对来自 的 CTE 中的列 qx
求和,创建一个名为 qxsum
的计算列,如下所示:
declare @idade int = 25
declare @sexo char = 'm'
;with cte as (
select
@idade as idade,
@sexo as sexo,
case when @sexo = 'm' then mor.Masculino else mor.Feminino end as qx,
cast((sum(1.0) over (order by @idade rows between current row and unbounded following)) as float) as qxsum
from Mortalidade as mor
where mor.Idade = @idade
union all
select
cte.idade + 1,
cte.sexo,
mor.qx,
cast((sum(cte.qx) over (order by @idade rows between current row and unbounded following)) as float) as qxsum
from cte
outer apply (
select
case when cte.sexo = 'm' then mor.Masculino else mor.Feminino end as qx
from Mortalidade as mor
where mor.Idade = cte.Idade + 1
) mor
where cte.Idade < 120
) select * from cte option (maxrecursion 0);
例如,SQL Fiddle 上面的 25 岁 qxsum
应该是 qx
从 25 岁到 120 岁的总和。
但是 SQL 服务器返回相同的值滞后一行,因为我犯了错误而且我不知道我犯了哪个错误。
您想按列 idade
而不是变量 @idade
(其值为所有行都相同)。此外,要为大于或等于当前行的所有年龄生成 window sum()
,您可以按 descending idade
(因此不需要 rows
帧)。
我发现使用递归 cte 生成 idade
的列表,然后在主查询中将 table 与 left join
一起使用更简单。
declare @idade int = 25;
declare @sexo char = 'm';
with cte as (
select @idade idade
union all select idade + 1 from cte where idade < 120
)
select
c.idade,
@sexo sexo,
case when @sexo = 'm' then m.masculino else m.feminino end as qx,
sum(case when @sexo = 'm' then m.masculino else m.feminino end)
over(order by c.idade desc) qxsum
from cte c
left join mortalidade m on m.idade = c.idade
order by c.idade
option (maxrecursion 0);
请注意,您应该将性别存储在不同的行而不是列中(这样可以避免需要条件逻辑)。
对于您的示例数据,this query yields:
idade | sexo | qx | qxsum
----: | :--- | :----------- | :------------
25 | m | 0.0019300000 | 28.0897400000
26 | m | 0.0019600000 | 28.0878100000
27 | m | 0.0019900000 | 28.0858500000
28 | m | 0.0020300000 | 28.0838600000
29 | m | 0.0020800000 | 28.0818300000
30 | m | 0.0021300000 | 28.0797500000
............. more rows here ............
111 | m | 1.0000000000 | 10.0000000000
112 | m | 1.0000000000 | 9.0000000000
113 | m | 1.0000000000 | 8.0000000000
114 | m | 1.0000000000 | 7.0000000000
115 | m | 1.0000000000 | 6.0000000000
116 | m | 1.0000000000 | 5.0000000000
117 | m | 1.0000000000 | 4.0000000000
118 | m | 1.0000000000 | 3.0000000000
119 | m | 1.0000000000 | 2.0000000000
120 | m | 1.0000000000 | 1.0000000000
SQL FIDDLE
我尝试对来自 qx
求和,创建一个名为 qxsum
的计算列,如下所示:
declare @idade int = 25
declare @sexo char = 'm'
;with cte as (
select
@idade as idade,
@sexo as sexo,
case when @sexo = 'm' then mor.Masculino else mor.Feminino end as qx,
cast((sum(1.0) over (order by @idade rows between current row and unbounded following)) as float) as qxsum
from Mortalidade as mor
where mor.Idade = @idade
union all
select
cte.idade + 1,
cte.sexo,
mor.qx,
cast((sum(cte.qx) over (order by @idade rows between current row and unbounded following)) as float) as qxsum
from cte
outer apply (
select
case when cte.sexo = 'm' then mor.Masculino else mor.Feminino end as qx
from Mortalidade as mor
where mor.Idade = cte.Idade + 1
) mor
where cte.Idade < 120
) select * from cte option (maxrecursion 0);
例如,SQL Fiddle 上面的 25 岁 qxsum
应该是 qx
从 25 岁到 120 岁的总和。
但是 SQL 服务器返回相同的值滞后一行,因为我犯了错误而且我不知道我犯了哪个错误。
您想按列 idade
而不是变量 @idade
(其值为所有行都相同)。此外,要为大于或等于当前行的所有年龄生成 window sum()
,您可以按 descending idade
(因此不需要 rows
帧)。
我发现使用递归 cte 生成 idade
的列表,然后在主查询中将 table 与 left join
一起使用更简单。
declare @idade int = 25;
declare @sexo char = 'm';
with cte as (
select @idade idade
union all select idade + 1 from cte where idade < 120
)
select
c.idade,
@sexo sexo,
case when @sexo = 'm' then m.masculino else m.feminino end as qx,
sum(case when @sexo = 'm' then m.masculino else m.feminino end)
over(order by c.idade desc) qxsum
from cte c
left join mortalidade m on m.idade = c.idade
order by c.idade
option (maxrecursion 0);
请注意,您应该将性别存储在不同的行而不是列中(这样可以避免需要条件逻辑)。
对于您的示例数据,this query yields:
idade | sexo | qx | qxsum ----: | :--- | :----------- | :------------ 25 | m | 0.0019300000 | 28.0897400000 26 | m | 0.0019600000 | 28.0878100000 27 | m | 0.0019900000 | 28.0858500000 28 | m | 0.0020300000 | 28.0838600000 29 | m | 0.0020800000 | 28.0818300000 30 | m | 0.0021300000 | 28.0797500000 ............. more rows here ............ 111 | m | 1.0000000000 | 10.0000000000 112 | m | 1.0000000000 | 9.0000000000 113 | m | 1.0000000000 | 8.0000000000 114 | m | 1.0000000000 | 7.0000000000 115 | m | 1.0000000000 | 6.0000000000 116 | m | 1.0000000000 | 5.0000000000 117 | m | 1.0000000000 | 4.0000000000 118 | m | 1.0000000000 | 3.0000000000 119 | m | 1.0000000000 | 2.0000000000 120 | m | 1.0000000000 | 1.0000000000