GROUPS BETWEEN 语法必须搭配 ORDER BY 使用,否则报错;它按排序后相同值分组计数,CURRENT ROW 指整个当前值组而非单行,不支持 RANGE,且仅 PostgreSQL 14+ 支持。

GROUPS BETWEEN 语法必须搭配 ORDER BY 使用
没有 ORDER BY 的窗口函数不能用 GROUPS 帧模式——它直接报错,比如 ERROR: window frame with GROUPS mode requires an ORDER BY clause。这是因为 GROUPS 是按“排序后相邻的相同值组”来数行的,没排序就不存在“组”的概念。
实操建议:
- 先确认
ORDER BY表达式能稳定生成可分组的序列(例如ORDER BY status, created_at比单独ORDER BY status更可靠) - 如果业务上本就不需要排序逻辑,别硬套
GROUPS;改用ROWS或直接聚合更合适 -
NULLS FIRST/LAST要显式写明,否则不同数据库对NULL分组行为不一致(PostgreSQL 默认NULLS LAST,可能把NULL单独成一组)
GROUPS CURRENT ROW 包含的是“当前值所在整个组”,不是单行
这是最容易误解的点:CURRENT ROW 在 GROUPS 模式下指“和当前行 ORDER BY 值完全相同的那一组所有行”,不是当前这一行本身。比如三行 status = 'active' 连续出现,GROUPS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 实际包含这三行,而非仅第三行。
常见错误现象:
- 预期移动平均只算最近 2 个状态组,结果窗口突然吞入 5 行(因为某组有 5 条相同值)
- 用
COUNT(*)配合GROUPS得到意外的大数值,误以为是 bug - 和
ROWS混用调试时,发现结果列数值完全对不上
GROUPS 不支持 RANGE,也不能和 RANGE 混用
GROUPS BETWEEN 和 RANGE BETWEEN 是互斥语法。试图写 RANGE GROUPS BETWEEN 或在同一个窗口定义里混用两者,会触发解析错误,如 ERROR: RANGE and GROUPS are mutually exclusive。
使用场景判断:
- 要按“逻辑语义组”(如订单状态批次、用户等级段)滑动统计 → 选
GROUPS - 要按“时间/数值跨度”(如过去 7 天、金额 ±100 范围)→ 选
RANGE - 要严格按物理行偏移(如前 2 行 + 当前行)→ 选
ROWS
注意:PostgreSQL 14+ 支持 GROUPS,但 MySQL 8.0 和 SQL Server 当前(2024)仍不支持该模式,写之前先查 SELECT version() 或文档。
UNBOUNDED FOLLOWING 在 GROUPS 中的行为容易被低估
GROUPS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING 不是从当前组开始往后无限取行,而是从当前组开始,取“排序顺序中当前位置之后的所有组”,每组内所有行全量包含。如果后续还有 10 个 status = 'pending' 行分散在不同位置,它们不会被纳入——只有紧接在当前组之后、且满足排序连续性的组才计入。
性能提示:
- 大表上用
GROUPS+UNBOUNDED FOLLOWING可能触发全窗口扫描,比等价的ROWS开销高 - 若只需当前组及下一组,明确写成
GROUPS BETWEEN CURRENT ROW AND 1 FOLLOWING,比依赖UNBOUNDED更可控 - 测试时用
SELECT *, COUNT(*) OVER (GROUPS ...)辅助观察实际帧覆盖哪些行,比纯脑补可靠得多
GROUPS 的核心复杂性在于它把“值相等性”和“排序位置”耦合在一起,而人脑习惯线性看行。只要记住:GROUPS 数的是组,不是行;组由 ORDER BY 定义,不由原始数据顺序定义。

















