WHERE作用于行、HAVING作用于组:WHERE在GROUP BY前筛选原始行,只能用列不能用聚合函数;HAVING在GROUP BY后筛选分组结果,可使用聚合函数和分组字段;执行顺序为FROM→WHERE→GROUP BY→HAVING→SELECT→ORDER BY。

WHERE 作用于行,HAVING 作用于组——这是最核心的区别。理解这一点,就能理清两者何时用、为何不能互换。
WHERE 在分组前筛选原始数据行
WHERE 子句在 GROUP BY 执行之前运行,它逐行检查每一条记录是否满足条件,不满足的行直接被过滤掉,根本不会参与后续的分组和聚合计算。
- 只能使用原始表中的列(或表达式),不能用聚合函数(如 COUNT()、SUM()、AVG())
- 例如:
WHERE salary > 5000是合法的;WHERE COUNT(*) > 10会报错 - 效率通常更高,因为它减少了后续分组的数据量
HAVING 在分组后筛选聚合结果
HAVING 子句在 GROUP BY 完成、各组聚合值(如每个部门的平均工资)已经算出之后才执行,它对“组”进行判断,决定哪些组保留在最终结果中。
- 可以使用聚合函数和分组字段(如
department、COUNT(*)、AVG(salary)) - 例如:
HAVING AVG(salary) > 8000是合法的;HAVING hire_date > '2020-01-01'则通常不合法(除非hire_date出现在 GROUP BY 中) - 它不能替代 WHERE 做行级过滤,否则会导致逻辑错误或性能下降
执行顺序决定了它们不可互换
SQL 的逻辑执行顺序是:FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY。这个顺序不是语法书写顺序,而是数据库内部处理数据的流程。
- WHERE 发生在 GROUP BY 之前,所以它看到的是“每一行”
- HAVING 发生在 GROUP BY 之后,所以它看到的是“每一组及其聚合值”
- 把本该写在 WHERE 的条件错写进 HAVING,会导致数据库先做无意义的分组,再丢弃结果,浪费资源
一个典型对比示例
查“每个部门平均工资超过 8000 的部门,且只统计 2019 年后入职的员工”:
- ✅ 正确写法:
SELECT department, AVG(salary)
FROM employees
WHERE hire_date > '2019-01-01' -- 行级过滤,提前筛人
GROUP BY department
HAVING AVG(salary) > 8000 -- 组级过滤,筛部门 - ❌ 错误写法:
WHERE AVG(salary) > 8000(语法错误)HAVING hire_date > '2019-01-01'(语义错误,hire_date 不在 GROUP BY 中,且未聚合)










