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;
-
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 相当于带聚合的全局过滤器。
系统功能强大、操作便捷并具有高度延续开发的内容与知识管理系统,并可集合系统强大的新闻、产品、下载、人才、留言、搜索引擎优化、等功能模块,为企业部门提供一个简单、易用、开放、可扩展的企业信息门户平台或电子商务运行平台。开发人员为脆弱页面专门设计了防刷新系统,自动阻止恶意访问和攻击;安全检查应用于每一处代码中,每个提交到系统查询语句中的变量都经过过滤,可自动屏蔽恶意攻击代码,从而全面防止SQL注入攻击
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 的前置剪枝能力。









