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

来源:这里教程网 时间:2026-02-28 20:39:01 作者:

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;
HAVING
后可直接用别名(如
cnt
)或原聚合表达式(如
COUNT(*) > 5
WHERE
只能作用于原始字段,例如
WHERE status = 'paid'
,且必须写在
GROUP BY
若同时需要行级过滤和分组后过滤,
WHERE
HAVING
可共存,顺序固定为:WHERE → GROUP BY → HAVING

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

因为

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

优先把能下推到
WHERE
的条件放过去,比如时间范围、状态码、非空校验
如果某条件依赖聚合结果(如“平均单价 > 100”),只能放
HAVING
,没有替代方案
在大表上,
HAVING COUNT(*) > 1
WHERE
多扫一遍数据,但有时配合索引(如联合索引覆盖
GROUP BY
字段)也能接受

没写 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 BY
HAVING
容易让人误解执行逻辑。

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

相关推荐