窗口函数只能出现在select或order by中,执行顺序在group by之后,因此不可用于group by、where或聚合计算中,必须通过子查询或cte嵌套使用。

因为 OVER 子句根本不能“放在 GROUP BY 后面”——它压根不允许出现在 GROUP BY 子句里,语法直接报错。这不是位置放得对不对的问题,而是 SQL 执行逻辑决定了它不可能在那里出现。
GROUP BY 阶段窗口函数还不存在
SQL 按固定顺序执行:FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY。窗口函数(如 SUM() OVER()、ROW_NUMBER() OVER())只允许写在 SELECT 或 ORDER BY 中,且实际计算发生在 SELECT 阶段——也就是 GROUP BY 完成之后。此时原始行已被压缩成聚合行,PARTITION BY dept 这种依赖明细行粒度的定义已无从谈起。
常见错误现象:
-
SELECT dept, AVG(salary) OVER(), COUNT(*) FROM emp GROUP BY dept→ 报错:window functions are not allowed in GROUP BY - 试图在
GROUP BY里写ROW_NUMBER() OVER(PARTITION BY dept)→ 直接语法拒绝
WHERE 和 GROUP BY 都不能引用窗口别名
即使你把窗口函数写在 SELECT 里并起了别名(如 rn AS ROW_NUMBER() OVER(...)),也不能在同层的 WHERE 或 GROUP BY 中用这个 rn。因为 WHERE 在 SELECT 之前执行,GROUP BY 作用于分组前的列或聚合结果,而窗口结果此时还没算出来。
正确做法只能是嵌套:
- 用子查询或 CTE 先算出窗口值,再在外层
WHERE rn > 1过滤 - 若需按窗口结果分组,必须先在内层产出该列,外层再
GROUP BY rn
PARTITION BY 不等于 GROUP BY,别想混着用
PARTITION BY dept 是逻辑切片,不物化分组;GROUP BY dept 是物理聚合,强制降维。两者语义冲突:一个要保留每行,一个要把多行变一行。强行共存只会让引擎无法确定数据粒度——它不知道该按员工算平均薪资,还是按部门输出一行。
典型误用场景:
- 想查“每个员工 + 所在部门平均薪资”,却写
SELECT name, salary, AVG(salary) FROM emp GROUP BY dept→ 报错,name和salary未聚合也未出现在GROUP BY - 正确解法是:
SELECT name, salary, AVG(salary) OVER (PARTITION BY dept),不加GROUP BY
真正容易被忽略的是:多个不同 PARTITION BY 的窗口函数(比如同时按 dept 算平均、按 role 算排名、全表算总和),可能触发多次排序或分组扫描——尤其在 PostgreSQL 和 SQL Server 中,性能退化比想象中更早。别只盯着语法通不通,得看执行计划里扫了几遍表。











