计算 SQL 服务器中的递减累积和
Compute a Decreasing Cumulative Sum in SQL Server
我想要实现的是非负列的累计和,其中每行减 1,但结果也必须是非负的。
例如,对于以下 table,对按 "ID" 列排序的 "VALUE" 列求和:
| ID | VALUE |
-----------------
| 1 | 0 |
| 2 | 0 |
| 3 | 2 |
| 4 | 0 |
| 5 | 0 |
| 6 | 3 |
| 7 | 0 |
| 8 | 2 |
| 9 | 0 |
| 10 | 0 |
| 11 | 0 |
| 12 | 0 |
我预计:
| ID | VALUE | SUM |
-------------------------
| 1 | 0 | 0 |
| 2 | 0 | 0 |
| 3 | 2 | 2 |
| 4 | 0 | 1 |
| 5 | 0 | 0 |
| 6 | 3 | 3 |
| 7 | 0 | 2 |
| 8 | 2 | 3 |
| 9 | 0 | 2 |
| 10 | 0 | 1 |
| 11 | 0 | 0 |
| 12 | 0 | 0 |
你的问题描述的不是很清楚。我最好的解释是你想从正数开始倒数,当你击中下一个时重新开始。
您可以使用非零值的累积和来定义组。然后对组使用累加和:
select t.*,
(case when max(value) over (partition by grp) < row_number() over (partition by grp order by id) - 1
then 0
else (max(value) over (partition by grp) -
(row_number() over (partition by grp order by id) - 1)
)
end) as my_value
from (select t.*,
sum(case when value <> 0 then 1 else 0 end) over (order by id) as grp
from t
) t
Here 是一个 db<>fiddle.
编辑:
让我印象深刻的是,您可能想要保留所有 "positive" 值并倒数 - 记住它们是否不会下降到零。唉,在这种情况下,我认为最简单的方法是递归 CTE:
with tn as (
select t.id, t.value, row_number() over (order by id) as seqnum
from t
),
cte as (
select tn.id, tn.value, tn.seqnum, tn.value as s
from tn
where id = 1
union all
select tn.id, tn.value, tn.seqnum,
(case when cte.s = 0
then tn.value
when tn.value = 0 and cte.s > 0
then cte.s - 1
-- when tn.value > 0 and cte.value > 0
else tn.value + cte.s - 1
end)
from cte join
tn
on tn.seqnum = cte.seqnum + 1
)
select *
from cte;
db<>fiddle 有两种解决方案。
我想要实现的是非负列的累计和,其中每行减 1,但结果也必须是非负的。
例如,对于以下 table,对按 "ID" 列排序的 "VALUE" 列求和:
| ID | VALUE |
-----------------
| 1 | 0 |
| 2 | 0 |
| 3 | 2 |
| 4 | 0 |
| 5 | 0 |
| 6 | 3 |
| 7 | 0 |
| 8 | 2 |
| 9 | 0 |
| 10 | 0 |
| 11 | 0 |
| 12 | 0 |
我预计:
| ID | VALUE | SUM |
-------------------------
| 1 | 0 | 0 |
| 2 | 0 | 0 |
| 3 | 2 | 2 |
| 4 | 0 | 1 |
| 5 | 0 | 0 |
| 6 | 3 | 3 |
| 7 | 0 | 2 |
| 8 | 2 | 3 |
| 9 | 0 | 2 |
| 10 | 0 | 1 |
| 11 | 0 | 0 |
| 12 | 0 | 0 |
你的问题描述的不是很清楚。我最好的解释是你想从正数开始倒数,当你击中下一个时重新开始。
您可以使用非零值的累积和来定义组。然后对组使用累加和:
select t.*,
(case when max(value) over (partition by grp) < row_number() over (partition by grp order by id) - 1
then 0
else (max(value) over (partition by grp) -
(row_number() over (partition by grp order by id) - 1)
)
end) as my_value
from (select t.*,
sum(case when value <> 0 then 1 else 0 end) over (order by id) as grp
from t
) t
Here 是一个 db<>fiddle.
编辑:
让我印象深刻的是,您可能想要保留所有 "positive" 值并倒数 - 记住它们是否不会下降到零。唉,在这种情况下,我认为最简单的方法是递归 CTE:
with tn as (
select t.id, t.value, row_number() over (order by id) as seqnum
from t
),
cte as (
select tn.id, tn.value, tn.seqnum, tn.value as s
from tn
where id = 1
union all
select tn.id, tn.value, tn.seqnum,
(case when cte.s = 0
then tn.value
when tn.value = 0 and cte.s > 0
then cte.s - 1
-- when tn.value > 0 and cte.value > 0
else tn.value + cte.s - 1
end)
from cte join
tn
on tn.seqnum = cte.seqnum + 1
)
select *
from cte;
db<>fiddle 有两种解决方案。