结论:用 rows between unbounded preceding and 1 preceding 或 rows between 1 following and unbounded following 配合聚合函数跳过当前行;exclude current row 仅 postgresql 14+ 支持,mysql 和 sql server 不兼容,跨库场景必须避免。

窗口函数里怎么跳过当前行做聚合
直接说结论:用 ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING 或 ROWS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING,配合 SUM()、AVG() 等聚合函数即可跳过当前行。别用 EXCLUDE CURRENT ROW——它只在 PostgreSQL 14+ 支持,MySQL 和 SQL Server 完全不认。
为什么不能直接写 EXCLUDE CURRENT ROW
很多开发者看到文档里有 EXCLUDE CURRENT ROW 就直接套用,结果在 MySQL 8.0 或 SQL Server 2019 上报错:Incorrect syntax near 'EXCLUDE'。这是因为标准 SQL 的 EXCLUDE 子句尚未被主流数据库广泛实现。PostgreSQL 14 是目前唯一稳定支持它的常用引擎,且仅限于 ORDER BY 存在、帧类型为 RANGE 或 ROWS 的场景。
-
EXCLUDE CURRENT ROW在 MySQL 中会触发语法错误,不是配置问题,是根本未解析 - SQL Server 把它当作非法 token,连执行计划都不生成
- 即使 PostgreSQL 支持,也要注意:若
ORDER BY列有重复值,RANGE帧下EXCLUDE CURRENT ROW可能意外排除多行
用 ROWS 框定范围来绕过当前行
最通用、跨库兼容的做法是显式定义窗口帧边界,把当前行“挡在外面”。关键不是“排除”,而是“不包含”——靠移动起点或终点实现。
- 计算“前面所有行的和(不含当前)”:
SUM(val) OVER (ORDER BY id ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) - 计算“后面所有行的平均值(不含当前)”:
AVG(val) OVER (ORDER BY id ROWS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING) - 要跳过当前行算滑动窗口(比如前2行+后2行):
SUM(val) OVER (ORDER BY id ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING EXCLUDE CURRENT ROW)—— 这句仅 PostgreSQL 14+ 有效,其他库必须拆成两段SUM(...) + SUM(...)
注意:1 PRECEDING 指紧邻上一行,不是“上一行及之前全部”;UNBOUNDED PRECEDING 才表示从分区开头起。顺序写反(比如 1 PRECEDING AND UNBOUNDED PRECEDING)会导致空窗口,结果全为 NULL。
实际场景中的坑:NULL 和排序稳定性
当 ORDER BY 字段含 NULL,不同数据库处理方式不同:MySQL 默认把 NULL 排最前,PostgreSQL 默认排最后。这直接影响 1 PRECEDING 能否正确锚定“上一行”。更麻烦的是,如果排序字段不唯一(比如多个相同时间戳),ROWS 框架仍按物理顺序切片,但结果不可预测——同一语句多次执行可能返回不同值。
- 解决方法:强制加唯一排序键,例如
ORDER BY created_at, id,确保每行位置确定 -
ROWS框架对NULL敏感,RANGE框架则可能因NULL导致整个帧为空(因为RANGE依赖值比较) - 若需严格排除当前行且跨库运行,宁可多写一层子查询或 CTE,也别依赖
EXCLUDE
真正麻烦的不是语法怎么写,而是你没法假设所有环境都支持同一套语义——尤其当 SQL 要跑在客户私有部署的旧版 MySQL 上时,EXCLUDE 就是个幻觉。











