order by 是窗口函数中定义行序的唯一子句,缺失则窗口帧无法展开,sum()等退化为静态聚合;order by 字段重复会导致累计结果不稳定,需添加唯一列保证确定性;asc/desc 改变累计方向但不改变 unbounded preceding 指向序列起点的本质。

ORDER BY 让 SUM() 从“全组求和”变成“逐行累加”
不加 ORDER BY 的 SUM() OVER (PARTITION BY x) 每行都返回该分组的固定总和;加上 ORDER BY y 后,它默认按 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 计算——也就是从分区第一行加到当前行。这不是语法糖,是窗口帧(frame)被激活的直接结果。
常见错误现象:SUM(amount) OVER (PARTITION BY user_id) 返回每条记录都是该用户全部金额,根本不是累计;而 SUM(amount) OVER (PARTITION BY user_id ORDER BY create_time) 才真正体现“第1笔、前2笔、前3笔…”的业务逻辑。
关键点在于:ORDER BY 不只是排序,它定义了“当前行”在序列中的位置,没有这个锚点,CURRENT ROW 就无从谈起,帧也就无法展开。
漏掉 ORDER BY 就等于放弃窗口的“顺序生命线”
ORDER BY 是窗口函数中唯一能建立行序的子句。一旦缺失,数据库只能把整个分区当作一个静态集合处理,所有聚合类窗口函数(SUM、AVG、COUNT)都会退化为无序聚合。
-
LAG()、LEAD()、FIRST_VALUE()全部失效或行为不可预测——因为“上一行”“首行”失去定义依据 -
LAST_VALUE()在无ORDER BY时永远只返回当前行值,不是真·末尾值 - 即使显式写了
ROWS BETWEEN ...,多数引擎也会忽略它,因缺少排序锚点,物理行号无法映射到逻辑位置
ORDER BY 字段重复会导致累计结果不稳定
如果 ORDER BY 字段存在重复值(比如多个订单同一天),不同执行可能产生不同累计路径——数据库可自由决定这些行的相对顺序,进而影响 CURRENT ROW 的“前面有哪些行”。
典型表现:
- 同一查询多次运行,某天的累计值在第2行和第3行之间跳变
-
SUM() OVER (ORDER BY sale_date ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)可能把同一天全部记录都算进“前一行”,实际变成“当天所有 + 前一天最后一笔” - 用
RANGE帧更危险:同日期所有行被捆成一组,SUM() OVER (ORDER BY sale_date RANGE ...)第一行就返回当天全部销量
解决办法:补唯一性,例如 ORDER BY sale_date, id 或 ORDER BY sale_date, created_at, order_id。
ORDER BY 方向改变累计语义,但不改变帧起点含义
ORDER BY date ASC 和 ORDER BY date DESC 对累计方向的影响是直观的,但容易误解的是 UNBOUNDED PRECEDING 的含义——它始终指排序后序列的起点,不随 ASC/DESC 改变。
也就是说:
-
SUM(sales) OVER (ORDER BY date ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW):截至当前日期的累计 -
SUM(sales) OVER (ORDER BY date DESC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW):从最后日期倒推,累计到当前日期(即“剩余未完成量”) -
SUM(sales) OVER (ORDER BY date DESC ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING):取当前行 + 后面两行,但由于已倒序,这“后面两行”其实是日期更早的两条记录
这个细节在写反向累计或滑动窗口时极易出错,必须结合排序方向重读帧定义。










