首页/数据/SQL 速查/ROWS 与 RANGE 帧的区别
聚合与窗口函数54 条

ROWS 与 RANGE 帧的区别

窗口帧决定函数看哪些行:ROWS 按物理行数,RANGE 按排序值的区间(并列值会一起进来);省略时默认 RANGE。

SQL 速查数据更新于 2026-10-13

窗口帧看哪些行

窗口函数默认看的是「从头到当前行」这个范围,范围本身是可以指定的,这就是窗口帧。帧有两种定义方式:按物理行数偏移,或者按排序列的取值区间偏移。两者在排序值唯一时结果一致,一旦出现并列值就分道扬镳——按取值算的帧会把所有并列行一起纳入。这也是同一段 SQL 在不同数据分布下算出不同累计值的根源。

基本信息

适用平台MySQL 8.0 / PostgreSQL 12 及以上
默认帧带排序的聚合窗口函数默认从起始行到当前行
两种模式按行数偏移与按取值区间偏移,并列值处理不同
常用边界无界前导、向前若干行、当前行、向后若干行、无界后随
取值偏移前提排序列必须支持算术运算,字符串列通常不可用

典型使用场景

  • 近若干天滑动平均:按日期排序后取固定行窗口
  • 逐行累计:从起算点累加到当前行的金额或数量
  • 同行对比:拿当前行与前后各一行做差值,看环比变化
  • 组内累计占比:先算组内累计,再除以组内合计
  • 榜单分档:在窗口内做排名后再取固定条数

两种帧的对比

两种帧的对比
-- 按行数算:严格最近两行(前一行加当前行)
SELECT dt, sales,
       SUM(sales) OVER (ORDER BY dt
                        ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS s_rows
FROM daily_sales;

-- 按取值算:同一天有多行时,这几行会被整组纳入帧
SELECT dt, sales,
       SUM(sales) OVER (ORDER BY dt
                        RANGE BETWEEN 1 PRECEDING AND CURRENT ROW) AS s_range
FROM daily_sales;

-- 逐行累计:从起始行加到当前行
SELECT dt, sales,
       SUM(sales) OVER (ORDER BY dt
                        ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_total
FROM daily_sales;

帧写法与用途

帧定义含义典型用途
按行偏移按物理行数确定范围滑动平均、前后行对比
按取值偏移按排序列取值区间确定范围日期区间累计,注意并列值
无界前导到当前行从起始行累计到当前行累计值、组内累计占比
当前行到无界后随从当前行向后全部剩余量、倒序累计
省略帧子句聚合窗口函数默认从起始到当前行逐行累计类需求
按取值偏移时,数值表示与排序列取值的距离,因此要求排序列能做加减运算。日期与时间戳可以配合区间写法使用,字符串列通常不行,会直接报错。
做逐行累计时优先用按行数偏移:同一天存在多条记录时,按取值算出的累计会让这几条记录互相「看得见」,得到相同的累计值,与逐行累计的预期不符。

易错点

  • 用按取值偏移做逐行累计:并列行会得到相同的累计值,与预期不符,逐行累计应明确写成按行偏移
  • 帧里写数字偏移却用了字符串排序列,语句直接失败,改按行偏移或换可运算的排序键
  • 省略帧子句后想当然地认为函数只看当前行:默认是从起始行累计,聚合结果被放大
  • 排序键不唯一又不指定稳定次序:相同取值之间的先后顺序不确定,窗口结果在多次执行间可能变化
  • 把窗口帧和分组混为一谈:分区决定分组范围,帧决定每组内部看多宽,两者要分别设置

数据来源与参考

  • MySQL 8.0 Reference Manual · Window Function Frames
  • PostgreSQL Documentation · Window Function Calls
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌