贝利信息

mysql中HAVING子句与WHERE子句的差异与应用

日期:2026-01-11 00:00 / 作者:P粉602998670
WHERE过滤行、HAVING过滤分组;WHERE在聚合前执行且不可用聚合函数,HAVING在GROUP BY后执行且必须依赖聚合结果;二者可共存,顺序为WHERE→GROUP BY→HAVING。

WHERE 是过滤行,HAVING 是过滤分组

WHERE 在聚合计算前就筛掉不满足条件的原始行,HAVING 则是在 GROUP BY 完成、聚合函数(如 COUNT()SUM())算出结果后,对分组结果再筛选。这意味着:WHERE 不能用聚合函数,而 HAVING 必须依赖分组或聚合结果。

WHERE 无法写 COUNT(*) > 5,但 HAVING 可以

常见错误是把本该放 HAVING 的条件误写进 WHERE,比如想查“订单数超过 5 的用户”,却写成:

SELECT user_id, COUNT(*) FROM orders WHERE COUNT(*) > 5 GROUP BY user_id;

这会直接报错 Invalid use of group function。正确写法是:

SELECT user_id, COUNT(*) AS cnt FROM orders GROUP BY user_id HAVING cnt > 5;

性能差异:WHERE 通常比 HAVING 更快

因为 WHERE 减少了参与分组的行数,数据库不用为被过滤掉的行做分组和聚合计算。而 HAVING 是在所有分组完成后再过滤,可能白白算了很多组。

没写 GROUP BY 时,HAVING 还能用吗?

可以,但语义变了:整个查询结果被视为一个分组。此时 HAVING 相当于带聚合的全局过滤器。

SELECT COUNT(*) AS total FROM users HAVING total > 1000;

这条语句不会返回任何行,除非总记录数真大于 1000。它等价于:

SELECT COUNT(*) AS total FROM users WHERE (SELECT COUNT(*) FROM users) > 1000;

虽然语法合法,但实际中极少这么用——更清晰的做法是用 SELECT + 应用层判断,或用子查询加 WHERE。滥用无 GROUP BYHAVING 容易让人误解执行逻辑。

真正容易被忽略的是:HAVING 的执行时机紧贴 GROUP BY 输出,哪怕只有一行结果,它也等聚合完成才介入。这个“等待聚合”的特性,决定了它永远无法替代 WHERE 的前置剪枝能力。