在 SQL Server 中计算递减的累积和

Posted

技术标签:

【中文标题】在 SQL Server 中计算递减的累积和【英文标题】:Compute a Decreasing Cumulative Sum in SQL Server 【发布时间】:2020-05-10 11:15:13 【问题描述】:

我要实现的是非负列上的累积总和,每行减 1,但结果也必须为非负数。

例如,对于下表,对按“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 |

【问题讨论】:

为什么第 8 行的值为“3”? 【参考方案1】:

您的问题描述得不是很好。我最好的解释是你想从正值开始倒数,当你碰到下一个时重新开始。

您可以使用非零值的累积和来定义组。然后对组使用累积和:

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 是一个 dbfiddle。

编辑:

令我震惊的是,您可能希望保留所有“正”值并倒计时——记住它们是否不会降为零。唉,我认为在这种情况下最简单的方法是递归 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;

dbfiddle 有两种解决方案。

【讨论】:

以上是关于在 SQL Server 中计算递减的累积和的主要内容,如果未能解决你的问题,请参考以下文章

使用带有 ORDER BY 的 SQL Server 查找累积总和

如何在 LINQ 中计算累积和?

在 PostgreSQL 中计算累积和

SQL 计算基于 Hive 列中先前值重置的累积总和

SQL - 计算产品的累积平均成本价

SQL 计算自当月第一天以来每天的累积 Distinct 计数