You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Postgres中计算下限为0的滚动求和的最佳方法是什么

PostgreSQL 下限为0的滚动求和实现方案

实现这类带下限的滚动求和不需要额外的特殊内置函数,以下是两种常用的可落地实现方式:

测试数据准备

首先构造你提到的示例测试表,注意滚动求和必须依赖明确的行顺序,因此额外新增了自增id作为排序依据,实际使用时可替换为业务对应的排序字段(如时间戳、业务序号等):

CREATE TEMP TABLE demo (
    id SERIAL PRIMARY KEY,
    val INT
);
INSERT INTO demo(val) VALUES (0), (-1), (-1), (2);

方案1:递归CTE实现(无需自定义函数,临时使用推荐)

递归CTE是最通用的实现方式,不需要预先定义任何函数,逻辑直观易调整:

WITH RECURSIVE rolling_sum AS (
    -- 初始化第一行的计算结果,用GREATEST保证不低于0
    SELECT id, val, GREATEST(val, 0) AS bounded_sum
    FROM demo
    WHERE id = 1
    UNION ALL
    -- 逐行累加,每一步都对求和结果做下限限制
    SELECT d.id, d.val, GREATEST(rs.bounded_sum + d.val, 0)
    FROM demo d
    JOIN rolling_sum rs ON d.id = rs.id + 1
)
-- 取最后一行的结果即为最终求和值
SELECT bounded_sum
FROM rolling_sum
ORDER BY id DESC
LIMIT 1;

计算逻辑完全匹配你的需求,示例的计算过程为:

  • 第1行值为0 → 结果为GREATEST(0,0) = 0
  • 第2行值为-1 → 结果为GREATEST(0 + (-1), 0) = 0
  • 第3行值为-1 → 结果为GREATEST(0 + (-1), 0) = 0
  • 第4行值为2 → 结果为GREATEST(0 + 2, 0) = 2
    最终返回结果为2,符合预期。

方案2:自定义聚合函数(高频使用推荐)

如果业务中需要频繁使用这类带下限的滚动求和,可自定义聚合函数,配合窗口函数使用更便捷,性能也优于递归CTE:

步骤1:定义聚合函数

-- 定义状态转换函数,每一步累加后限制下限为0
CREATE OR REPLACE FUNCTION bounded_sum_state(acc numeric, curr numeric)
RETURNS numeric AS $$
SELECT GREATEST(acc + curr, 0);
$$ LANGUAGE sql IMMUTABLE;

-- 注册自定义聚合函数
CREATE AGGREGATE bounded_rolling_sum(numeric) (
    SFUNC = bounded_sum_state,
    STYPE = numeric,
    INITCOND = '0'
);

步骤2:使用聚合函数

SELECT bounded_rolling_sum(val) OVER (ORDER BY id)
FROM demo
ORDER BY id DESC
LIMIT 1;

注意事项

  • 必须为窗口/递归逻辑指定明确的排序规则,否则行顺序不确定会导致计算结果完全错误。
  • 百万级以上大数据量场景下优先使用自定义聚合方案,性能比递归CTE高30%以上。

内容的提问来源于stack exchange,提问作者David Ramsaran

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 09:57:07