sum() over的order by不能省略,否则每行返回全表总和而非累计值;必须用order by指定累加顺序(如order by order_date),配合partition by可实现分组内独立累计。

为什么SUM() OVER的ORDER BY不能省略?
不加ORDER BY的SUM() OVER()等价于全表求和,不是累计——它会把所有行的值加起来,每行都显示同一个总数。累计必须明确“按什么顺序累加”,比如按日期、订单ID或时间戳。数据库不知道你心里想的是“从最早到最晚”,得明说。
常见错误现象:SUM(sales) OVER()返回每行都是500万,而实际想看第1天10万、第2天25万、第3天48万……这种阶梯式增长。
- 必须写成
SUM(sales) OVER(ORDER BY order_date)或OVER(ORDER BY created_at ASC) - 如果日期有重复,建议补上唯一列防歧义,例如
ORDER BY order_date, order_id - 默认窗口帧是
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,这正好符合累计语义,不用额外写
如何按销售员分组做各自累计?
用PARTITION BY切分窗口,让每个销售员独立累计,互不影响。漏掉它会导致张三的业绩被李四的订单拉高——这是线上报表最常出错的地方。
使用场景:销售日报、区域业绩追踪、多门店日销趋势对比。
- 正确写法:
SUM(sales) OVER(PARTITION BY salesperson_id ORDER BY order_date) -
PARTITION BY必须在ORDER BY之前,顺序不能颠倒 - 分区字段类型要一致,比如别拿
salesperson_id(INT)和salesperson_code(VARCHAR)混用,否则可能分出空组
ORDER BY里用DESC会怎样?
累计方向反转:从最后一行开始累加,越靠前的记录值越小。这不是bug,是设计行为——但多数业务场景要的是“从早到晚”的自然累计,所以ASC才是默认且安全的选择。
性能影响:ORDER BY字段如果有索引(如order_date上的B-tree索引),窗口函数执行会快很多;没索引时,大表可能触发临时文件排序,拖慢查询。
- 显式写
ORDER BY order_date ASC比省略更清晰,避免团队新人误解 - 不要用
ORDER BY id DESC假装实现“倒序累计”,那只是把数据排反了,累计逻辑仍是正向的(从结果集第一行加到最后一行) - 某些旧版MySQL(ERROR 1064,先确认版本
NULL值会影响累计结果吗?
会,但只影响参与计算的行:SUM()天然忽略NULL,所以某行sales为NULL,它不计入当前累计值,但窗口位置仍在——下一行的累计值 = 前面所有非NULL值之和。
容易被忽略的地方:前端展示时,如果把NULL销售额渲染成“0”,而数据库里其实是NULL,累计值就比预期少;反过来,如果业务要求把NULL当0算,得先COALESCE(sales, 0)。
- 稳妥做法:
SUM(COALESCE(sales, 0)) OVER(PARTITION BY team ORDER BY order_date) - 检查原始数据中
sales列的NULL比例,高的话需和业务方确认含义:是未录单?退货?还是异常数据? - 注意
COALESCE不能放在OVER()外面,否则窗口计算完再转,已失去意义
PARTITION BY)、按什么序(ORDER BY)。其余都是围绕这两点防错和对齐业务语义。真正上线前,务必用含重复日期、NULL、跨分区边界的几条真实数据手工验算一遍结果。










