SUM() OVER()基本写法是SUM(col) OVER(PARTITION BY group_col ORDER BY order_col),缺一不可:PARTITION BY划分组,ORDER BY确保组内逐行累加,漏掉任一则无法实现正确累计。

什么是 SUM() OVER() 的基本写法
直接用 SUM(column) OVER(PARTITION BY group_col ORDER BY order_col) 就能实现分组内按顺序累计求和。关键不是“先 GROUP BY 再 SUM”,而是让窗口函数在每个分组内部按指定顺序逐行累加。
比如销售表 sales 有 region、date、amount,想看每个地区按日期递增的累计销售额:
SELECT region, date, amount,
SUM(amount) OVER(PARTITION BY region ORDER BY date) AS cumsum
FROM sales;注意:没写 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 也没关系——这是默认行为,但显式写出来更防误读。
PARTITION BY 和 ORDER BY 缺一不可吗
缺 PARTITION BY 就变成全表累计;缺 ORDER BY 则报错(PostgreSQL/SQL Server)或结果不确定(MySQL 8.0+ 要求必须有,否则提示 warning)。没有排序就没有“累计”的意义,数据库不知道从哪开始加到哪。
-
PARTITION BY region:限定累计只在同地区内发生 -
ORDER BY date:决定累计的先后顺序,必须是确定性排序(避免用ORDER BY id但id不唯一) - 如果想按金额从高到低累计,就写
ORDER BY amount DESC,但要注意重复值可能导致相同累计值“堆叠”
遇到重复排序键(如同一天多笔订单)怎么办
当 ORDER BY 列存在重复值(例如同一天多个 amount),不同数据库对“当前行”的界定可能不一致,导致累计值跳变或重复。最稳妥的是补一个唯一列做二级排序:
SUM(amount) OVER( PARTITION BY region ORDER BY date, id -- 加 id 确保顺序唯一 )
常见坑:
- 用
ORDER BY date, amount仍可能不唯一(同天同金额) - MySQL 8.0 对
ORDER BY中非确定列会警告,但不报错,结果可能和预期不符 - 如果业务上“同天就是并列”,需确认是否接受累计值在该日最后一行才更新
和传统 GROUP BY + SUM() 的性能差异在哪
窗口函数不改变行数,SUM() OVER() 返回每行对应位置的累计值;而 GROUP BY 会聚合掉明细行。两者用途根本不同,不能互换,但容易误以为“加了 PARTITION BY 就等于 GROUP BY”。
性能上:
- 大数据量时,
ORDER BY是主要开销点,索引能明显加速(建议在(region, date)上建联合索引) - 某些旧版 MySQL(ERROR 1064: You have an error in your SQL syntax
- 如果只要最终累计值(比如每个地区的总和),别硬套
OVER(),用GROUP BY region更轻量
真正需要累计逻辑时,SUM() OVER() 是目前最直接可靠的方案,但顺序定义必须清晰,否则结果看似对、实则不可复现。

















