rows between按物理行号取数,严格控制行数;range between按排序列值划范围,相同值行全纳入。二者在重复值、空缺或非连续时间下结果差异显著,误用会导致统计错误。

ROWS BETWEEN 看行号,RANGE BETWEEN 看值;用错一个,结果可能完全不对,尤其在有重复值、空缺值或非连续时间字段时。
ROWS BETWEEN 是物理窗口:只数“第几行”
它把排序后的结果当成一个固定队列,严格按位置取行。比如 ROWS BETWEEN 1 PRECEDING AND CURRENT ROW 永远只拉当前行和它正上方那一行——不管这两行的 order by 列值差多少。
- 适合场景:需要固定行数滑动(如“最近3条记录的平均值”)、ID 唯一且递增、日期已去重并补全
- 性能好:数据库可直接跳指针,基本不扫描额外数据
- 常见错误:用
ROWS BETWEEN 6 PRECEDING AND CURRENT ROW算“7天移动平均”,但原始数据里某天没销售记录 → 实际只取了6天甚至更少 - 注意:
CURRENT ROW就是当前这一行,不包含值相等的其他行
RANGE BETWEEN 是逻辑窗口:按值划范围
它不关心行号,只看 ORDER BY 列的值。比如 RANGE BETWEEN INTERVAL '7 days' PRECEDING AND CURRENT ROW 表示:取所有 sale_date 在 [当前行日期 − 7天, 当前行日期] 内的行,哪怕中间隔了20行、值重复5次、或某天根本没数据。
- 适合场景:基于真实业务跨度的计算(如“过去7天销售额”、“价格在±10元内的订单总和”)
- 性能差:每行都要重新比对值范围,无法走索引(除非排序列高度有序且无空缺)
- 常见错误:
RANGE BETWEEN 2 PRECEDING AND CURRENT ROW中的2不是“两行”,而是“排序列值减2”,若排序列是字符串或浮点数,会直接报错或返回空 - 注意:含
NULL的行默认被排除在所有RANGE窗口外;多个相同值的行会被同时纳入窗口
ORDER BY 列有重复值时,差异最明显
假设你按 score 排序,数据是 [1,2,2,2,3,4],当前行 score = 2:
-
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING→ 取上一行(1)、当前行(2)、下一行(2),共3行 -
RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING→ 范围是 [2−1, 2+1] = [1,3],取所有score∈ {1,2,3} 的行 → 共5行(1,2,2,2,3) - 如果误以为
RANGE也能控制“行数”,结果就会严重高估聚合值
MySQL / PostgreSQL / Hive 中的兼容性要点
不是所有数据库都支持任意形式的 RANGE 边界:
- MySQL 8.0+ 支持
RANGE BETWEEN INTERVAL 'N days' PRECEDING,但不支持RANGE BETWEEN 2 PRECEDING(数字不能直接用于非数值排序列) - PostgreSQL 和 Oracle 允许
RANGE BETWEEN 10 PRECEDING,前提是排序列是数值型,且表达式类型匹配(如int对int) - Hive 要求
ORDER BY必须是单列,且RANGE的PRECEDING/FOLLOWING值必须是常量表达式 - 所有主流引擎中,
RANGE默认要求ORDER BY存在;而ROWS即使没ORDER BY也能用(此时窗口是整分区)
真正容易被忽略的点是:当你换了一个数据源或升级了数据库版本,RANGE 的行为可能静默变化——比如旧版 MySQL 把不支持的 RANGE 语句自动降级为 ROWS,新版则直接报错。上线前务必用真实分布的数据验证边界行为,而不是只测主键递增的模拟表。










