WHERE在分组前过滤行,HAVING在分组后过滤组;WHERE不能用聚合函数和别名,HAVING可以;HAVING通常需配合GROUP BY使用,且不走索引,过滤粒度为组而非行。
WHERE 和 HAVING 的根本区别在哪
WHERE 是在分组前过滤行,HAVING 是在分组后过滤组。如果你写了 WHERE COUNT(*) > 1,MySQL 会直接报错,因为 COUNT(*) 是聚合函数,WHERE 阶段还没开始分组,根本不可用。
常见错误现象:Unknown column 'COUNT(*)' in 'where clause' 或查询结果为空但逻辑上应该有数据。
- WHERE 后只能跟原始字段(如
status、created_at),不能用SUM()、AVG()、COUNT()等 - HAVING 后可以跟聚合函数,也可以跟 SELECT 中的别名(如
HAVING total > 100,前提是 SELECT 里写了SUM(price) AS total) - 执行顺序是:FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT
HAVING 必须配合 GROUP BY 使用吗
绝大多数情况下是的。单独写 HAVING price > 100 不报错,但行为等价于 WHERE,且失去语义——MySQL 会隐式忽略 HAVING 并当作普通过滤条件处理,容易引发误解。
真正需要 HAVING 的场景,一定是“先分组,再判断组是否符合条件”。比如查出每个部门平均薪资超 15000 的部门,就必须写:
SELECT dept, AVG(salary) AS avg_sal FROM employees GROUP BY dept HAVING avg_sal > 15000;
如果漏掉 GROUP BY dept,AVG(salary) 会算全表均值,HAVING 就只剩一个组可筛,完全失去分组筛选意义。
HAVING 能用索引加速吗
不能。HAVING 是对临时分组结果集做的过滤,发生在内存或临时表中,不走任何索引。性能瓶颈往往出现在 GROUP BY 阶段本身。