在MySQL的查询语句中,having和where都承担着过滤数据的作用,但二者的设计逻辑和适用场景有本质不同,很多新手在编写带分组统计的查询时经常会用错这两个子句。

执行时机不同
where子句的执行时机早于having子句。where会在数据分组之前对原始数据进行过滤,过滤掉不符合条件的记录后再进行分组操作;而having是在数据完成分组、聚合计算之后,对分组后的结果集进行过滤。
过滤对象不同
where的过滤对象是单条原始记录,它针对的是表中每一行的具体字段值进行判断;having的过滤对象是分组后的结果集,通常是对每个分组的聚合计算结果进行判断。
对聚合函数的支持不同
where子句中不能直接使用聚合函数作为过滤条件,因为此时聚合计算还没有执行,无法获取聚合结果;having子句可以直接使用聚合函数作为过滤条件,因为此时分组和聚合计算已经完成。
语法差异示例
我们通过一个学生成绩表的查询案例来直观对比二者的用法,假设有一张student_score表,结构如下:
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | int | 记录ID |
| student_name | varchar | 学生姓名 |
| subject | varchar | 学科名称 |
| score | int | 考试成绩 |
where子句使用示例
如果要查询所有数学成绩大于80分的学生记录,直接用where过滤单条记录即可:
-- 查询数学成绩大于80分的学生记录 SELECT student_name, subject, score FROM student_score WHERE subject = '数学' AND score > 80;
having子句使用示例
如果要查询平均分大于85分的学科,需要先按学科分组计算平均分,再用having过滤分组结果:
-- 查询平均分大于85分的学科 SELECT subject, AVG(score) as avg_score FROM student_score GROUP BY subject HAVING avg_score > 85;
二者结合使用示例
如果需求是查询数学学科中,平均分大于80分的班级(假设表中还有class字段),就需要先where过滤出数学学科的记录,再分组后用having过滤平均分:
-- 查询数学学科平均分大于80分的班级 SELECT class, AVG(score) as avg_score FROM student_score WHERE subject = '数学' GROUP BY class HAVING avg_score > 80;
适用场景总结
- 当需要过滤原始单条记录,且过滤条件不涉及聚合函数时,优先使用where子句,比如过滤指定字段的取值、指定时间范围的记录等。
- 当需要对分组后的结果进行过滤,且过滤条件涉及聚合函数计算结果时,必须使用having子句,比如过滤分组后的总数量、平均值、最大值等。
- 二者可以结合使用,先通过where过滤掉不需要参与分组的原始数据,减少分组计算的数据量,提升查询效率,再通过having过滤分组结果。
注意:where子句的过滤操作发生在分组之前,因此where条件中不能出现聚合函数,否则会直接报语法错误;而having只能配合GROUP BY子句使用,没有分组操作时单独使用having会不符合语法规范。