必须加ORDER BY,否则SUM() OVER(PARTITION BY ...)返回组内总和而非累计和;正确写法为SUM(amount) OVER(PARTITION BY category ORDER BY create_time),并用COALESCE(amount, 0)处理NULL,MySQL需8.0+才支持窗口函数。

SQL里用SUM() OVER()计算分组内累计和,必须加ORDER BY
不加ORDER BY的SUM() OVER(PARTITION BY ...)只会返回每组总和,不是累计值。累计和本质是“按某列排序后逐行累加”,所以ORDER BY不是可选项,而是逻辑必需项。
常见错误现象:SUM(amount) OVER(PARTITION BY category)跑出来每行都一样——那是组内总和,不是累计和。
- 正确写法必须形如:
SUM(amount) OVER(PARTITION BY category ORDER BY create_time) -
ORDER BY字段应具备业务意义(如时间、序号),且尽量非空;若存在相同值,建议补上唯一字段(如id)避免不确定排序 - 默认窗口帧是
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,刚好满足累计需求,无需显式声明
遇到NULL值时SUM累计和会中断,得提前处理
SUM()遇到NULL会跳过,但累计逻辑不能因此断开。比如某行amount为NULL,后续行的累计值会基于它前面的非空值继续加,看起来像“漏算”,其实是符合SQL标准行为——但业务上常要求把NULL当0。
- 稳妥做法:用
COALESCE(amount, 0)包裹原始字段,再套SUM() OVER() - 别用
IFNULL或ISNULL,函数名因数据库而异;COALESCE是标准SQL,兼容MySQL/PostgreSQL/SQL Server - 示例:
SUM(COALESCE(amount, 0)) OVER(PARTITION BY dept ORDER BY seq)
在MySQL 5.7或更早版本里无法直接用SUM窗口函数
MySQL从8.0才支持窗口函数。如果你执行SUM() OVER()报错ERROR 1064或提示语法错误,先查版本:SELECT VERSION();。5.7及之前只能靠变量模拟,但极易出错。
- 变量方案(仅限MySQL 5.7):
@sum := @sum + COALESCE(t.amount, 0)配合JOIN (SELECT @sum := 0) AS _,但必须严格保证ORDER BY在最外层生效,否则累计顺序错乱 - 强烈建议升级到MySQL 8.0+,窗口函数语义清晰、性能更好、无需担心变量作用域问题
- PostgreSQL和SQL Server 2012+原生支持,无此限制
ORDER BY字段类型影响累计结果稳定性
如果用字符串字段(如order_no)做ORDER BY,而该字段含前导零或长度不一(如'ORD001' vs 'ORD1000'),字典序排序会导致'ORD1000'排在'ORD002'前面,累计顺序错乱。
- 时间类字段优先选
TIMESTAMP或DATETIME,而非格式化后的字符串 - 序号类字段确保是数值型;若只能是字符串,考虑用
LPAD补齐位数,或用CAST(order_no AS SIGNED)转整数(MySQL) - 测试时务必检查边界数据:首行、末行、重复值、NULL、最大最小值附近是否累计正确
ORDER BY字段的业务合理性与数据质量。哪怕语法全对,只要排序依据本身不可靠,累计和就是个精致的错误。

















