首页/数据/SQL 速查/累计求和(running total)
聚合与窗口函数54 条

累计求和(running total)

用 SUM(...) OVER (ORDER BY …) 计算截至当前行的累计值:销售额累计、账户流水余额等经典场景。

SQL 速查数据更新于 2026-10-13

累计求和是什么

累计求和用 SUM(...) OVER (ORDER BY ...) 实现:在保留明细行的同时给出截至当前行的累计值,典型场景是销售额累计与账户流水余额。默认窗口帧是从分区开头到当前行,所以结果天然是累计值而非组内总量;想算组内总量就去掉 ORDER BY,只保留 PARTITION BY。要留意并列值的处理:默认 RANGE 帧会把排序键相同的行算进同一个累计结果,需要严格逐行累加时改用 ROWS 帧。

基本信息

语法SUM(值) OVER (PARTITION BY 分组 ORDER BY 排序 [ROWS 帧])
默认帧RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
累计与总量带 ORDER BY 得累计值,只写 PARTITION BY 得组内总量
并列处理默认 RANGE 帧会把排序键相同的并列行一起算入
严格逐行写 ROWS UNBOUNDED PRECEDING 按物理顺序累加
适用平台MySQL 8.0+ 与 PostgreSQL 均支持

典型使用场景

  • 销售额累计:按天累计出月内累计营收曲线
  • 账户流水余额:每笔交易后显示当前余额
  • 进度统计:累计完成量与目标对比
  • 库存滚动变化:按时间累计出入库数量
  • 用户成长值:累计积分随事件递增
  • 分组累计:每个客户各自的累计消费金额

示例

示例
-- 全局累计
SELECT d, amount,
       SUM(amount) OVER (ORDER BY d) AS running_total
FROM sales;

-- 按客户分组累计
SELECT customer_id, d, amount,
       SUM(amount) OVER (PARTITION BY customer_id ORDER BY d
                         ROWS UNBOUNDED PRECEDING) AS running_total
FROM sales;

-- 组内总量(去掉 ORDER BY)
SELECT customer_id, d, amount,
       SUM(amount) OVER (PARTITION BY customer_id) AS customer_total
FROM sales;

窗口写法对照

写法结果适用
OVER (ORDER BY d)全局累计单一序列的累计值
OVER (PARTITION BY k ORDER BY d)每组内累计多客户或多设备的流水
OVER (PARTITION BY k)组内总量每行附带该组总额
ROWS UNBOUNDED PRECEDING严格逐行累加排序键可能重复时
RANGE 默认帧并列行合并计算需要按值而非按行的累计
排序键重复时默认 RANGE 帧会让并列行得到相同的累计值,看起来像跳变;需要严格逐行累加就用 ROWS 帧。
累计结果依赖排序键的确定顺序,排序键不唯一时补主键做次级键,否则同一份数据两次计算的累计值可能不同。
需要「截至上一天的累计」时把条件写成严格小于当天,或在窗口前先用子查询按天聚合,避免同日多行导致重复累加。

使用要点

  • 排序键要唯一或补主键,结果才可复现
  • 用 ROWS 帧替代默认 RANGE 帧,得到严格逐行的累计
  • 先按天聚合再开窗,避免一日多行导致累计跳变
  • 分区键与排序键上建索引可减少额外排序
  • 展示时要注明累计口径:含当日还是不含当日
  • 大表上先过滤时间范围再开窗,减少参与排序的数据量

易错点

  • 排序键不唯一时累计值出现跳变或重复,业务方以为数据有误
  • 忘记 PARTITION BY 导致多个实体的流水被混在一起累计
  • 把累计值当成组内总量使用,报表数字口径全错
  • 窗口计算前没有先去重或按天聚合,同一天多行导致重复累加
  • 在超大结果集上直接开窗,排序与临时表开销拖慢查询

数据来源与参考

  • MySQL 8.0 Reference Manual · Window Function Concepts
  • PostgreSQL Documentation · Window Functions
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌