SQL 中 WHERE 和 HAVING 的本质区别

12次阅读

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

SQL 中 WHERE 和 HAVING 的本质区别

WHERE 作用于行,HAVING 作用于组——这是最核心的区别。理解这一点,就能理清两者何时用、为何不能互换。

WHERE 在分组前筛选原始数据行

WHERE 子句在 GROUP BY 执行之前运行,它逐行检查每一条记录是否满足条件,不满足的行直接被过滤掉,根本不会参与后续的分组和聚合计算。

  • 只能使用原始表中的列(或表达式),不能用聚合函数(如 count()、SUM()、AVG())
  • 例如:WHERE salary > 5000 是合法的;WHERE COUNT(*) > 10 会报错
  • 效率通常更高,因为它减少了后续分组的数据量

HAVING 在分组后筛选聚合结果

HAVING 子句在 GROUP BY 完成、各组聚合值(如每个部门的平均工资)已经算出之后才执行,它对“组”进行判断,决定哪些组保留在最终结果中。

  • 可以使用聚合函数和分组字段(如 departmentCOUNT(*)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 中,且未聚合)

text=ZqhQzanResources