groups 不是标准 sql 子句,真正实现逻辑行组排名的是 partition by 配合 rank() 等窗口函数;partition by 划分数据块但不压缩行数;rank() 跳号、dense_rank() 紧接、row_number() 严格递增;having 不能过滤窗口结果,需用子查询或 cte。

GROUPS 不是标准 SQL 的子句,也没有 GROUPS 这个关键字 —— 你很可能混淆了 GROUP BY 和窗口函数中的 GROUPS 模式(仅存在于某些数据库的 WINDOW 定义中,如 PostgreSQL 的 RANGE / ROWS / GROUPS 框架),但它从不单独作为查询子句出现。
真正能处理“具有相同排名的逻辑行组”的,是窗口函数配合 PARTITION BY 和排名函数,而不是 GROUPS。
PARTITION BY 是分组排名的核心
PARTITION BY 把数据按指定列拆成多个逻辑块,每个块内独立计算排名或聚合。它不是 GROUP BY,不压缩行数,也不要求 SELECT 列必须聚合或出现在 PARTITION BY 中。
- 常见错误:把
PARTITION BY当成GROUP BY用,结果发现行数没变、聚合没生效 - 正确理解:
PARTITION BY只是“划区域”,后续的ROW_NUMBER()、RANK()、DENSE_RANK()才决定怎么排
例如,按部门分组并给员工按薪资排名:
SELECT name, department, salary, RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dept_rank FROM employees;
- 同一部门内薪资相同的人会得到相同
dept_rank(RANK()跳号,DENSE_RANK()不跳) - 不同部门的排名互不影响
RANK() vs DENSE_RANK() vs ROW_NUMBER() 的实际差异
这三者都依赖 ORDER BY,但对“相同值”的处理逻辑不同:
-
ROW_NUMBER():严格按顺序编号,哪怕值相同也绝不重复(1,2,3,4…) -
RANK():相同值获得相同名次,后续跳过占用位数(1,2,2,4…) -
DENSE_RANK():相同值获得相同名次,后续紧接(1,2,2,3…)
举个例子,某部门四人薪资为 [9000, 8000, 8000, 7000]:
-
ROW_NUMBER()→ 1,2,3,4 -
RANK()→ 1,2,2,4 -
DENSE_RANK()→ 1,2,2,3
选哪个取决于业务定义:“并列第二”之后是“第四”还是“第三”。
HAVING 不能用于过滤窗口函数结果
常见误区:想筛出“部门内排名前3的员工”,写成:
SELECT * FROM ( SELECT *, RANK() OVER (PARTITION BY department ORDER BY salary DESC) r FROM employees ) t WHERE r <p>✅ 正确:用子查询或 CTE + <code>WHERE</code><br> ❌ 错误:试图在外部加 <code>HAVING r —— <code>HAVING</code> 只作用于 <code>GROUP BY</code> 分组后的聚合结果,而窗口函数不产生分组,<code>r</code> 不是聚合值,不能进 <code>HAVING</code></code></p><hr><p>真正容易被忽略的点是:<strong><code>PARTITION BY</code> 不改变原始行数,也不触发聚合;要压缩成每组一行,必须搭配 <code>GROUP BY</code> 或显式聚合;要保留明细+分组内计算,才用窗口函数</strong>。混用场景时,先想清楚目标是“汇总”还是“标注”,再选机制。</p>











