MySQL 8.0+ 直接用 SUM(value) OVER (PARTITION BY group_col ORDER BY order_col) 实现累计求和,必须写 ORDER BY 否则变为组内总和;PostgreSQL 9.4+ 和 SQL Server 2012+ 写法相同,且强制要求 ORDER BY;旧版 MySQL 用变量模拟风险高,易因求值顺序不确定而结果错误。

MySQL 8.0+ 用 SUM() 窗口函数最直接
MySQL 5.7 及更早版本不支持窗口函数,强行用变量实现容易出错;8.0+ 直接用 SUM(value) OVER (PARTITION BY group_col ORDER BY order_col) 就行。关键点是:PARTITION BY 定义分组边界,ORDER BY 决定累计顺序——没它就变成组内总和,不是“累计”。
常见错误:漏写 ORDER BY,或误把排序字段写成常量(如 ORDER BY 1),导致累计逻辑混乱;另外,NULL 值在排序中默认排最前,可能打乱业务预期,建议显式处理(如 ORDER BY IFNULL(date_col, '1970-01-01'))。
PostgreSQL 和 SQL Server 同样依赖 OVER() 语法
PostgreSQL 9.4+、SQL Server 2012+ 都支持标准窗口函数,写法和 MySQL 8.0+ 一致,但注意:ORDER BY 子句必须存在,否则报错 Window function requires an ORDER BY clause。SQL Server 还支持 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW(默认行为),但显式写出更安全,避免未来版本语义变更影响。
性能提示:窗口函数会在内存中维护运行聚合状态,如果分组内数据量极大(比如单组百万行),可能触发临时磁盘排序,建议对 ORDER BY 字段建索引。
旧版 MySQL(5.7 及之前)用变量模拟风险高
典型写法是声明变量 @sum := 0,再在 SELECT 中做 @sum := @sum + value,但问题极多:
- MySQL 不保证 SELECT 中表达式求值顺序,变量更新可能乱序
- GROUP BY + 变量组合极易出错,尤其当 GROUP BY 字段和排序字段不一致时
- 无法在子查询或视图里可靠复用,调试困难
真要兼容老版本,优先考虑应用层累加,或者用自连接(LEFT JOIN + ON a.group = b.group AND a.order ),虽然慢但逻辑确定。
ROW_NUMBER() 和 RANK() 不解决累计合计问题
有人混淆“行号”和“累计和”,误用 ROW_NUMBER() OVER (PARTITION BY x ORDER BY y) 或 RANK()。这两个函数只返回序号,跟数值累加无关。即使你把它们和 SUM() 混用,也不会自动产生累计效果——必须明确用 SUM(col) OVER (...)。
另一个坑:用 COUNT(*) OVER (...) 代替 SUM(value) OVER (...),结果是计数而非求和,业务含义完全不同。
累计合计本质是“按序叠加”,核心约束只有两个:分组依据、叠加顺序。窗口函数天然匹配这个语义;绕开它用其他手段,基本是在给自己埋执行不可靠、维护难的雷。

















