rows between current row and unbounded following 定义向后累计窗口,起点为当前行、终点为分区末尾,用于计算“当前行及之后所有行”的聚合值;默认order by窗口帧为range between unbounded preceding and current row。

用 ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING 定义向后累计范围
窗口函数默认的 ORDER BY 窗口帧(frame)是 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,只包含当前行及之前。要统计“当前行之后的剩余值”,必须显式指定向后延伸的帧——关键是把起点设为 CURRENT ROW,终点设为 UNBOUNDED FOLLOWING。
常见错误是写成 ROWS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING,这会跳过当前行,漏掉它本身;而需求通常是“包含当前行 + 后续所有行”,所以起点必须是 CURRENT ROW。
示例:按销售时间排序,算出“从当前订单起,到年底为止的总销售额”:
SELECT
order_date,
amount,
SUM(amount) OVER (
ORDER BY order_date
ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
) AS remaining_total
FROM sales;
SUM()、COUNT()、AVG() 都支持向后窗口,但语义不同
不是所有聚合函数在向后窗口下都符合直觉。比如 COUNT(*) 统计的是“当前行及之后的行数”,而 AVG(amount) 是对这些行的 amount 求均值——注意它不自动忽略 NULL,若后续行有 NULL amount,AVG 会跳过它们(标准 SQL 行为),但 COUNT(*) 仍会计入。
-
SUM(amount):安全,常用,无歧义 -
COUNT(*):返回剩余行数(含当前行),适合做“还剩几条”类统计 -
AVG(amount):需确认业务是否允许跳过NULL;若要包含NULL作分母,得改用COUNT(*)和SUM()手动算
ORDER BY 必须存在,且方向影响结果含义
没有 ORDER BY,SQL 标准不允许定义 ROWS BETWEEN ... FOLLOWING,多数数据库(PostgreSQL、SQL Server、Doris)会直接报错:window frame with FOLLOWING requires ORDER BY。MySQL 8.0+ 虽允许无 ORDER BY,但此时“FOLLOWING”失去意义,行为未定义,别依赖。
另外,ORDER BY 的升序/降序决定“之后”指什么:
- 按时间
ASC:后续是更晚的记录(推荐,符合自然时间流) - 按金额
DESC:后续是金额更大或相等的记录——这通常不是“剩余”的本意,容易误用
务必检查 ORDER BY 列的业务含义,而不是只看语法能否执行。
性能和 NULL 处理:大表慎用,空值需显式判断
向后窗口需要数据库从末尾反向扫描或构建完整排序缓冲区,比向前窗口(UNBOUNDED PRECEDING)更容易触发内存溢出或临时磁盘写入,尤其在没索引的 ORDER BY 列上。
NULL 值在 ORDER BY 中的默认位置因数据库而异(PostgreSQL 默认 NULLS LAST,MySQL 8.0 默认 NULLS FIRST),会导致“当前行之后”实际包含或排除大量 NULL 行。如果业务要求把 NULL 视为有效数据参与统计,应显式写出:
ORDER BY order_date NULLS LAST
否则可能发现 remaining_total 在某些行突然变小——其实是 NULL 被排到了前面,挤出了本该计入的非空行。











