SQL中WHERE与HAVING的区别详解及实战用法
在SQL查询构建中,准确区分 WHERE 和 HAVING 是提升查询效率的关键。二者虽都用于数据过滤,但作用阶段截然不同:WHERE 在分组前筛选单行数据,不能直接使用聚合函数;而 HAVING 在分组后筛选结果集,通常用于处理聚合后的条件判断。
核心差异与工作流
理解这两者区别的最佳方式是将其置于完整的SQL执行逻辑中考察。一条包含过滤逻辑的查询语句,其执行顺序决定了数据何时被拦截:
- FROM & JOIN:确定数据源。
- WHERE:对原始数据进行逐行过滤(此时尚未分组)。
- GROUP BY:将筛选后的数据进行归类聚合。
- HAVING:对聚合后的各组数据进行筛选。
- SELECT:输出最终列。
第1步:使用 WHERE 进行基础过滤
目的:减少进入分组计算的数据量,从而提升性能。
规则:作用于表或视图的行级别。可以使用任意列名进行比较。
禁忌:因为此时数据尚未分组,所以 WHERE 内部绝对不能包含 COUNT(), SUM(), AVG() 等聚合函数。
典型场景:筛选出薪资大于5000的员工记录。
SELECT department, COUNT(*)
FROM employees
WHERE salary > 5000;
-- 这里先过滤掉低薪员工,剩下的再按部门统计
第2步:使用 HAVING 进行分组后筛选
目的:在统计完成之后,剔除不符合特定“整体”条件的组。
规则:作用于 GROUP BY 产生的结果集(即“组”)。
特点:专门配合聚合函数使用,例如“筛选出员工总数超过10人的部门”。
SELECT department, COUNT(*) as emp_count
FROM employees
WHERE salary > 5000
GROUP BY department
HAVING COUNT(*) > 5;
-- 统计出人数大于5人的高薪员工部门
常见误区与最佳实践
很多初学者容易混淆两者的位置。有一个直观的类比记忆法:
- WHERE 像是在进考场前先查身份证(筛选人)。
- HAVING 像是查分后筛选不及格的班级(筛选分组结果)。
为什么不建议滥用 HAVING?
如果过滤条件不涉及聚合函数(如 SELECT * FROM table HAVING id > 1),虽然语法上可能允许某些数据库执行,但属于极低效的做法。原因如下:
- 性能损耗:使用
HAVING往往意味着必须先执行全表扫描并进行分组聚合,最后才做筛选;而WHERE可以在读取数据时直接丢弃不匹配的行,大幅减轻后续步骤的压力。 - 可读性:违背常规逻辑,增加维护成本。
综合应用示例
假设我们有一张订单表 orders,要求查询出:2023年以后创建的、且平均订单金额超过100元的客户ID。
我们需要结合两者:利用 WHERE 过滤时间范围以减少数据量,利用 HAVING 过滤平均值高的用户组。
SELECT customer_id, AVG(amount) as avg_amount
FROM orders
WHERE created_at >= '2023-01-01' -- WHERE: 先过滤掉旧年份订单
GROUP BY customer_id -- GROUP BY: 按客户分组
HAVING AVG(amount) > 100 -- HAVING: 再过滤掉均值不够的客户组
总结
掌握 WHERE 与 HAVING 的本质区别,关键在于把握“时间线”。凡是能用 WHERE 提前拦截的条件,绝不留给 HAVING;只有涉及“统计后的结果”(如总数、平均值、最大值比较),才必须移动到 HAVING 中进行判断。这种搭配不仅能确保逻辑正确,更是写出高性能 SQL 的基础规范。
以上就是SQL语句中where和having的区别的详细内容,更多关于SQL过滤与优化的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









