窗口函数必须配合OVER子句生效,frame_clause决定“当前行算什么范围内的值”;不显式指定时,有ORDER BY默认RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,无ORDER BY则默认ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING。

窗口函数必须配合 OVER 子句才能生效,而 frame_clause 是其中最易被忽略、却对结果影响最大的部分——它直接决定“当前行算什么范围内的值”。不写 frame_clause 不代表没窗口,而是用默认规则,常导致 SUM 累加变全表求和、移动平均失效、LAG 取错行。
为什么 ORDER BY 一加,SUM 就变成累积和了?
因为只要写了 ORDER BY,默认 frame_clause 就是 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW。这意味着:每一行的 SUM() 都只算从分区开头到当前行(含)的所有值。
- 没写
ORDER BY→ 默认ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING→ 整个分区所有行都参与计算 - 写了
ORDER BY但没写frame_clause→ 默认按RANGE算,且包含所有值相等的“并列行”(注意:RANGE对重复排序值会扩大窗口) - 想严格按物理行偏移(比如前1行+当前行+后1行),必须显式写
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
ROWS 和 RANGE 的区别到底在哪?
ROWS 数的是“第几行”,RANGE 比的是“值是否落在某个数值区间内”。同一个 ORDER BY salary,两者的计算边界可能完全不同。
- 当
salary有重复值(如 5000 出现三次),RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING会把所有 salary=5000 的行全包进来,哪怕它们物理上相隔很远 -
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING只取紧邻的三行,不管 salary 是否相同 - 时间类字段(如
order_date)用RANGE BETWEEN INTERVAL '7' DAY PRECEDING AND CURRENT ROW才有意义;数字主键或序号列,一律优先用ROWS
如何写出一个可靠的移动平均(3日均值)?
关键不是套公式,而是锁定行为:必须用 ROWS,明确指定物理偏移,并确保排序字段无重复、无空值。
- 错误写法:
AVG(sales) OVER (ORDER BY order_date)→ 默认RANGE,日期重复时窗口爆炸 - 正确写法:
AVG(sales) OVER (ORDER BY order_date, order_id ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)→ 用order_id打破日期重复歧义,再限定三行 - 如果日期有缺失(比如跳过周末),
ROWS仍按“行数”算,不是“日历天数”;真要按自然日滑动,得用RANGE BETWEEN INTERVAL '2' DAY PRECEDING AND CURRENT ROW(仅 PostgreSQL / Oracle 支持,MySQL 8.0+ 不支持INTERVAL在RANGE中)
哪些场景必须显式写 frame_clause?
只要逻辑依赖“相对当前行的固定行数范围”,就不能依赖默认行为。
- 计算同比/环比:需要
LAG(sales, 12) OVER (ORDER BY year_month),但若某月数据缺失,LAG会跳过空月取更早的值 —— 这时你真正想要的是“12个月前那行”,就得靠ROWS+ 稳定排序保证位置准确 - 识别连续登录:用
date - INTERVAL 'row_num - 1' DAY做分组,前提是ROW_NUMBER()的排序必须严格连续且无间隙,否则得先用ROWS框定范围再校验 - Top-N 截断:虽然
RANK()本身不依赖frame_clause,但如果你在子查询里嵌套SUM() OVER (PARTITION BY category ORDER BY sales DESC ROWS UNBOUNDED PRECEDING)来算累计占比,不写ROWS就可能因默认RANGE把同销量商品全捆在一起,导致累计值突变
真正难的不是语法,而是想清楚:你要的“窗口”,是按行号数、按值大小扩、还是按时间跨度滑?选错 ROWS/RANGE,或者漏写 frame_clause 却以为逻辑没问题,是线上 SQL 结果漂移最常见的根源之一。

















