UNBOUNDED PRECEDING 是窗口帧边界关键字,必须配合 ORDER BY 和 ROWS BETWEEN ... AND ... 使用;单独使用或位置错误均报错,且需结合 PARTITION BY 明确分区范围。

UNBOUNDED PRECEDING 不是用来“统计历史总计”的独立语法,它必须配合 ROWS BETWEEN ... AND ... 和 ORDER BY 出现在窗口函数的 OVER 子句里。单独写 UNBOUNDED PRECEDING 会报错。
UNBOUNDED PRECEDING 必须和 ROWS BETWEEN 搭配使用
- 它不是函数参数,而是窗口帧边界关键字,只在
ROWS或RANGE模式下生效 - 常见正确写法是:
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW - 错误写法示例(直接报错):
-
SUM(amount) OVER (UNBOUNDED PRECEDING)→ 缺少ORDER BY和帧定义 -
SUM(amount) OVER (ORDER BY date UNBOUNDED PRECEDING)→ 语法非法,关键字位置错误
-
你真正要写的是一整套窗口定义,比如:
SUM(amount) OVER (ORDER BY create_time ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
为什么必须写 ORDER BY?
-
CURRENT ROW是相对概念,没有排序就没有“当前行”的参照系 - SQL Server 2012+ 会直接拒绝执行不带
ORDER BY的累计类窗口函数(如报错:The function 'SUM' must have an ORDER BY clause) - 即使绕过(比如用
RANGE模式省略ORDER BY),结果也不可靠:重复值会被合并累加,导致跳变
常见踩坑点:
- 用主键
id替代业务时间字段排序 → id 可能乱序插入,累计顺序错乱 -
ORDER BY列含NULL→ 默认排在最前或最后,影响首尾行累计值 - 多列排序时没加
ASC/DESC显式声明 → 依赖默认行为,不同版本可能表现不一致
PARTITION BY 决定“历史”的范围边界
-
UNBOUNDED PRECEDING不是指“全表第一行”,而是“当前分区的第一行” - 如果你要算每个用户的累计消费,必须写:
PARTITION BY user_id ORDER BY create_time - 如果漏掉
PARTITION BY,用户 A 的第 1 笔订单可能被累加进用户 B 的第 5 笔结果里
注意:
- 分区字段必须是确定性表达式(不能是
GETDATE()、NEWID()等) -
PARTITION BY和ORDER BY的数据类型最好匹配索引字段,否则性能下降明显 - 若分区后某组只有 1 行,
UNBOUNDED PRECEDING就等价于只算这一行
UNBOUNDED PRECEDING 的语义很干净:它不参与计算逻辑,只划定帧起点。真正决定“怎么累加”“累加谁”的,是 ORDER BY 的顺序、PARTITION BY 的分组粒度,以及你选的是 ROWS 还是 RANGE。这三个要素缺一不可,任意一个写错,累计值就不可信。

















