where在分组前过滤行,having在分组后过滤组;where不能用聚合函数,having可以;执行顺序为from→where→group by→having→select→order by。

WHERE 在分组前过滤行,HAVING 在分组后过滤组——这是最核心的区别。理解这一点,就能避开90%的误用场景。
WHERE:作用于原始数据行
WHERE 子句在 GROUP BY 之前执行,只对单条记录做判断,不能使用聚合函数(如 COUNT()、SUM()、AVG() 等)。
- 适用于筛选“哪些行参与后续计算”,比如
WHERE status = 'active' - 条件中出现的字段必须是 SELECT 列表中出现的非聚合列,或原表中存在的列
- 效率通常更高,因为能尽早减少数据量
HAVING:作用于分组结果
HAVING 子句在 GROUP BY 之后执行,是对已分组后的结果集进行筛选,支持聚合函数和别名。
- 常用于“哪些组满足条件”,比如
HAVING COUNT(*) > 5 - 可以引用 SELECT 中定义的聚合别名,例如
SELECT dept, COUNT(*) AS cnt FROM emp GROUP BY dept HAVING cnt > 3 - 不能单独存在,必须配合 GROUP BY(除非查询本身隐含分组,如全聚合查询)
执行顺序决定行为边界
SQL 实际执行流程是:FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY。这个顺序解释了为什么 WHERE 看不到聚合结果,而 HAVING 能看到。
- 如果想筛“订单金额总和超过1万元的客户”,必须用 HAVING,因为需要先按客户分组再算 SUM
- 如果想筛“2024年下的订单”,用 WHERE 即可,时间条件在单行上就能判断
- 错误写法示例:
WHERE COUNT(*) > 10—— 语法报错,COUNT 此时尚未生成
一个典型对比示例
查每个部门员工数,只显示人数 ≥ 2 的部门:
- ✅ 正确(HAVING):
SELECT dept, COUNT(*) FROM emp GROUP BY dept HAVING COUNT(*) >= 2 - ❌ 错误(WHERE):
SELECT dept, COUNT(*) FROM emp WHERE COUNT(*) >= 2 GROUP BY dept—— WHERE 不允许用聚合 - ⚠️ 可行但逻辑不同(WHERE + HAVING 结合):
SELECT dept, COUNT(*) FROM emp WHERE salary > 5000 GROUP BY dept HAVING COUNT(*) >= 2—— 先筛高薪员工,再统计部门人数并过滤










