where作用于分组前的原始行,不能用聚合函数;having作用于分组后的结果,必须配合group by,可使用聚合函数和select别名。

WHERE 和 HAVING 不是“能不能用聚合函数”的问题,而是“数据还没分组”和“已经分组完”的根本阶段差异。选错就查不到想要的结果,甚至报错。
WHERE 不能用 COUNT()、AVG() 这类聚合函数
因为 WHERE 执行时,每一行都还是独立的原始记录,数据库还没开始分组,更没算出 COUNT() 或 AVG() 的值。你写 WHERE COUNT(*) > 1,MySQL 直接报错 Invalid use of group function。
- 能用的条件:字段原值,比如
WHERE salary > 5000、WHERE status = 'active' - 不能用别名:即使 SELECT 里写了
salary AS pay,WHERE 里也不能写WHERE pay > 5000,它看不到这个别名 - 多表 JOIN 时,WHERE 先筛再连,能显著减少中间结果集大小
HAVING 必须跟 GROUP BY 一起出现
单独写 HAVING SUM(amount) > 1000 会报错 You have an error in your SQL syntax —— MySQL 要求 HAVING 前必须有 GROUP BY(除非某些旧版本或特定引擎允许空 GROUP BY,但不可靠)。
- 能用聚合函数:
HAVING COUNT(*) >= 3、HAVING AVG(score) >= 85 - 能用 SELECT 中的别名:比如
SELECT dept, AVG(salary) AS avg_sal FROM emp GROUP BY dept HAVING avg_sal > 6000是合法的 - 列引用受限:HAVING 里只能用 GROUP BY 的列,或 SELECT 中出现的聚合表达式,不能引用未出现在 GROUP BY 或聚合里的普通列
执行顺序决定性能和结果逻辑
SQL 实际执行顺序是:FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY。这意味着:
-
WHERE越早过滤掉无用行,后续分组的数据量就越小,性能越好 -
HAVING是在所有分组计算完之后才跑,如果本该用 WHERE 筛掉 90% 的数据,却放到 HAVING 里,等于让数据库白算一堆组 - 例如查“订单数超 5 的客户”,
WHERE order_date >= '2025-01-01'应放在 WHERE,而不是等分组完再用 HAVING 去筛时间范围
最容易被忽略的一点:HAVING 不是 WHERE 的“加强版”,它是 GROUP BY 的配套开关。写 HAVING 之前,先问自己——我是不是真需要分组?如果只是单行筛选,就别碰 HAVING,它不光多余,还会误导别人读代码。











