SQL累加求和不能只用SUM(),因为SUM()是聚合函数,会将多行压缩为单行,无法保留原始行级结构并计算“截至当前行”的累计值;必须使用SUM() OVER()窗口函数,且必须包含ORDER BY子句定义累加顺序,否则默认返回分区总和而非逐行累计。

SQL累加求和为什么不能只用SUM()?
因为普通 SUM() 是聚合函数,一用就压缩行数,没法保留原始每行数据的同时显示“到当前行为止的累计值”。必须用窗口函数才能既分组/排序,又逐行计算累积和。
SUM() OVER() 的基本写法和排序关键
累加结果是否正确,完全取决于 ORDER BY 子句——它定义了“累加顺序”。没有 ORDER BY,SUM() OVER() 会默认对整个分区做总和(即每行都显示同一值),不是累加。
-
SUM(amount) OVER (ORDER BY create_time):按时间顺序累加,最常用 -
SUM(amount) OVER (PARTITION BY user_id ORDER BY create_time):先按用户分组,再在组内按时间累加 - 如果
create_time有重复,建议补上唯一字段(如id)避免排序不确定:ORDER BY create_time, id
常见错误:NULL值、类型不匹配、ORDER BY漏写
实际执行时容易卡在这几个地方:
-
SUM()遇到NULL自动跳过,但如果字段是字符串或布尔型,会报错:ERROR: function sum(text) does not exist,需显式转类型:SUM(amount::numeric) - 忘记写
ORDER BY,结果每行都是全量总和,看着像“没累加” - 在 MySQL 8.0 之前不支持窗口函数,会直接报错
ERROR 1064;确认版本用SELECT VERSION(); - PostgreSQL 中若排序字段含 NULL,默认排在最前,可能让第一行累加值异常,可加
NULLS LAST控制
和GROUP BY + 子查询比,窗口函数有什么实际优势?
核心是“不丢行、不嵌套、一次扫描”。比如要查订单表每笔订单的累计金额+客户名+下单时间,用子查询得关联或写两层嵌套,而窗口函数一行搞定:
SELECT user_id, create_time, amount, SUM(amount) OVER (PARTITION BY user_id ORDER BY create_time) AS cum_amount FROM orders;
性能上,窗口函数通常比相关子查询快 2–5 倍,尤其数据量过万后。但注意:如果 PARTITION BY 字段基数极高(比如每行都不同),窗口框架维护开销会上升,这时得权衡是否真需要逐行累加。
真正容易被忽略的是排序稳定性——业务上“同一秒多个订单”,仅靠时间戳无法保证累加顺序与插入顺序一致,补主键或自增 ID 才算兜底。

















