最直接查高于平均值的记录是用子查询返回单个AVG值,如WHERE salary > (SELECT AVG(salary) FROM employees);需注意括号、NULL处理、相关子查询及窗口函数替代方案。

子查询写在 WHERE 里直接对比平均值
想查高于平均值的记录,最直接的方式是把 AVG() 放进子查询,作为 WHERE 条件里的比较值。注意:子查询必须返回单个标量值,否则会报错 Subquery returns more than 1 row。
常见错误是忘了加括号、或者在子查询里漏了 GROUP BY 导致逻辑错乱(比如误以为按部门算平均,却没分组)。
- 子查询必须用圆括号包裹,例如:
WHERE salary > (SELECT AVG(salary) FROM employees) - 不能在子查询里引用外层表字段再不加相关子查询(correlated subquery),否则可能慢或出错
- 如果要按部门分别找“高于本部门平均薪资”的员工,就得用相关子查询:
WHERE e.salary > (SELECT AVG(e2.salary) FROM employees e2 WHERE e2.dept_id = e.dept_id)
用窗口函数替代子查询更高效
当数据量大、且需要同时显示平均值和原始数据时,AVG() OVER() 比子查询快得多——避免重复扫描表,也省去嵌套结构。
但要注意:窗口函数不能直接用于 WHERE,因为 WHERE 执行阶段窗口函数还没计算。得用 SELECT ... FROM (subquery) WHERE avg_salary... 包一层。
- 正确写法:
SELECT name, salary FROM (SELECT name, salary, AVG(salary) OVER() AS avg_salary FROM employees) t WHERE salary > avg_salary
- 别写成
WHERE salary > AVG(salary) OVER()—— 语法错误,OVER不能出现在WHERE - 如果只查一条记录,
AVG窗口函数和子查询性能差异不大;查全表或分组时,窗口函数优势明显
NULL 值会让 AVG 和比较结果变诡异
AVG() 默认忽略 NULL,但如果你的字段本身有 NULL,而业务上希望把 NULL 当作 0 或最小值参与计算,就得先处理——否则 salary > (SELECT AVG(salary) ...) 会漏掉那些 salary IS NOT NULL 但实际低于“非空平均值”的行。
- 检查是否有
NULL:SELECT COUNT(*), COUNT(salary) FROM employees,两个数不等就说明有空值 - 想把
NULL视为 0 再算平均:AVG(COALESCE(salary, 0)) - 但更常见的是过滤掉空值:
WHERE salary IS NOT NULL写在子查询里,保持语义清晰
MySQL 8.0+ 和 PostgreSQL 支持 CTE,让逻辑更清晰
把平均值单独抽成一个 WITH 子句,可读性比嵌套子查询高很多,也方便复用(比如同时查高于/低于平均的两组数据)。
不过 CTE 在老版本 MySQL(
- 标准写法:
WITH avg_val AS (SELECT AVG(salary) AS avg_salary FROM employees) SELECT name, salary FROM employees, avg_val WHERE salary > avg_salary
- PostgreSQL 允许在
FROM中直接 JOIN CTE;MySQL 要么用逗号隐式 JOIN,要么用CROSS JOIN - CTE 不会提升性能(只是语法糖),但能避免手误写错子查询多次

















