ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 定义从分区首行到当前行的物理行范围,用于累计计算;必须配合 ORDER BY 使用,按排序位置而非值大小纳入行,与 RANGE 的逻辑值范围有本质区别。

UNBOUNDED PRECEDING 必须和 ORDER BY 一起出现,否则语法报错;它本身不定义窗口终点,终点得靠 CURRENT ROW、UNBOUNDED FOLLOWING 或显式范围来补全。
UNBOUNDED PRECEDING 单独写会报错
很多人一上来就写 SUM(sales) OVER (ORDER BY date UNBOUNDED PRECEDING),结果 SQL 直接报错:Incorrect syntax near 'UNBOUNDED'。这是因为 UNBOUNDED PRECEDING 是窗口帧(frame)的一部分,不能脱离 ROWS BETWEEN ... AND ... 或 RANGE BETWEEN ... AND ... 独立存在。
- ✅ 正确写法必须带
ROWS BETWEEN或RANGE BETWEEN - ❌ 错误写法:
OVER (ORDER BY date UNBOUNDED PRECEDING) - ❌ 错误写法:
OVER (PARTITION BY dept ORDER BY salary UNBOUNDED PRECEDING)
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 是最常用组合
这是累计求和、运行总计(running total)、逐行最大值等场景的默认窗口。它的含义是:从当前分组的第一行,到当前行(含),物理上取所有前面的行(包括自己)。
- 适用于需要“截至当前”的聚合,比如每月销售额累计、用户第 N 次下单金额总和
- 注意:如果没写
PARTITION BY,那就对整个结果集做累计;写了则按分区各自累计 -
ROWS是按实际行数计,相同ORDER BY值的多行不会被合并(这点和RANGE不同)
示例:SUM(amount) OVER (PARTITION BY user_id ORDER BY order_time ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
RANGE 和 ROWS 在 UNBOUNDED PRECEDING 下行为差异很大
当 ORDER BY 列存在重复值时,ROWS 和 RANGE 的窗口边界表现完全不同:
-
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW:只包含物理位置在当前行及之前的所有行,哪怕order_time相同,也严格按扫描顺序逐行累加 -
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW:把所有order_time ≤ 当前行 order_time的行都纳入窗口 —— 可能一次性拉进多行,甚至跳过中间“空档” - 如果排序列是主键或唯一时间戳,两者结果一致;否则建议优先用
ROWS,行为更可控
省略窗口子句时,UNBOUNDED PRECEDING 是隐式默认值
当你只写 OVER (PARTITION BY x ORDER BY y),SQL Server / PostgreSQL / Oracle 都会自动补上 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW。但 MySQL 8.0+ 默认是 RANGE 模式,这点容易踩坑。
- 显式写出
ROWS BETWEEN ...能避免跨数据库行为不一致 - 如果真想覆盖全部分区(比如求每个部门最高薪),就得写
UNBOUNDED FOLLOWING或干脆省略ORDER BY - 别依赖隐式规则——尤其在写跨平台 SQL 或交接代码时,显式声明更安全
真正难的不是写对 UNBOUNDED PRECEDING,而是想清楚:你到底要按「行位置」还是「值范围」切窗口,以及当前 ORDER BY 列是否足够唯一。这两个问题不厘清,后面的结果偏差很难排查。

















