窗口函数avg() over不能用于where子句,因其执行顺序在where之后;必须通过cte或子查询先物化结果,再在外层过滤。

AVG OVER 不能直接用于 WHERE 子句
这是最常踩的坑:你写 WHERE salary > AVG(salary) OVER (PARTITION BY dept_id),SQL 会报错——Window function is not allowed in WHERE clause。窗口函数只能出现在 SELECT 或 HAVING(配合 GROUP BY)中,不能参与行级过滤。
用子查询或 CTE 提前算出部门均值
必须把 AVG() OVER 的结果先“物化”成一列,再在外层过滤。CTE 更清晰,也避免重复计算:
WITH dept_avg AS (
SELECT id, name, dept_id, salary,
AVG(salary) OVER (PARTITION BY dept_id) AS dept_avg_salary
FROM employees
)
SELECT id, name, dept_id, salary
FROM dept_avg
WHERE salary > dept_avg_salary;
注意:AVG() 默认忽略 NULL,如果部门里有 NULL 薪资记录,均值只基于非空值计算;若需保留 NULL 占位,得提前用 COALESCE(salary, 0) 处理,但语义就变了。
用 JOIN 关联聚合结果也能实现,但要小心 NULL 和重复
如果你倾向用传统 JOIN,得先单独聚合部门均值,再关联原表:
SELECT e.id, e.name, e.dept_id, e.salary FROM employees e INNER JOIN ( SELECT dept_id, AVG(salary) AS dept_avg FROM employees GROUP BY dept_id ) d ON e.dept_id = d.dept_id WHERE e.salary > d.dept_avg;
-
INNER JOIN会自动排除dept_id IS NULL的记录,而 CTE 方式保留原表所有行(只是dept_avg_salary为NULL,后续>判断结果为UNKNOWN,不命中) - 如果一个员工属于多个部门(比如多对多中间表未拆开),JOIN 可能导致重复行,CTE 更安全
性能和可读性取舍:窗口函数比 GROUP BY + JOIN 略快
在大数据量下,AVG() OVER 通常只需一次扫描,而子查询方式要两次:一次算均值,一次关联过滤。但差别往往不大,优先选 CTE——它把逻辑拆解清楚,后续加 ROW_NUMBER() 或累计统计也方便扩展。
真正容易被忽略的是:部门均值是浮点数,比较时别用 = 判断相等;另外,如果业务要求“高于且不等于”,就得明确写 >,而不是 >=——哪怕 AVG() 算出来刚好是整数,底层仍是 numeric 或 double 类型。










