GROUP BY 和 HAVING 核心注意事项
ps:如果这篇帖子对于还在找工作和找实习的你有所帮助,可以关注我,给本贴点赞、评论、收藏并订阅专栏;同时不要吝啬您的花花
一、核心概念(先理解基础)
- GROUP BY:按指定字段将数据分组,对每组计算聚合结果(如平均分、总人数),实现同类数据汇总。
- HAVING:仅对分组后的结果筛选,区别于WHERE(分组前过滤原始行)。
结合「学生-成绩表」,以下详解核心注意事项,搭配实例便于实操验证。
二、关键注意事项(附示例)
1. SELECT子句的字段严格受限(核心坑点)
GROUP BY分组后,SELECT仅能出现「GROUP BY分组字段」或「聚合函数」(SUM/AVG/COUNT等)。
❌ 错误示例:
-- 错误:name既非分组字段,也非聚合函数(MySQL开启ONLY_FULL_GROUP_BY报错) SELECT major, name FROM student GROUP BY major;
✅ 正确示例:
-- 按专业分组,查各专业学生数、平均年龄 SELECT major, COUNT(student_id) AS stu_count, AVG(age) AS avg_age FROM student GROUP BY major;
2. WHERE 与 HAVING 的核心区别(不可混用)
作用时机 | 分组前过滤行 | 分组后过滤组 |
能否用聚合函数 | ❌ 不能 | ✅ 可以 |
位置 | GROUP BY 之前 | GROUP BY 之后 |
❌ 错误示例:
-- 错误:WHERE不能用聚合函数 SELECT student_id, AVG(score) AS avg_score FROM score WHERE AVG(score) > 80 GROUP BY student_id;
✅ 正确示例:
-- 查计算机专业学生中,Java科目平均分>80的学生ID和平均分 SELECT sc.student_id, AVG(sc.score) AS avg_java_score FROM score sc JOIN student s ON sc.student_id = s.student_id WHERE sc.subject = 'Java' AND s.major = '计算机' GROUP BY sc.student_id HAVING AVG(sc.score) > 80;
3. HAVING 不能脱离 GROUP BY 单独使用
HAVING专为分组结果服务,无GROUP BY时语义混乱,等价于WHERE,不推荐使用。
❌ 不推荐:
SELECT name, age FROM student HAVING age > 20;
✅ 正确用法:
-- 按专业分组,保留学生数>2的专业 SELECT major, COUNT(student_id) AS stu_count FROM student GROUP BY major HAVING COUNT(student_id) > 2;
4. 多字段分组的顺序与粒度
多字段分组按顺序逐级细化粒度,先按第一个字段分组,再在组内按第二个字段分组。
-- 按「专业+科目」分组,查每组平均分 SELECT s.major, sc.subject, AVG(sc.score) AS avg_score FROM student s JOIN score sc ON s.student_id = sc.student_id GROUP BY s.major, sc.subject;
5. HAVING中是否可以不使用聚合函数
结论:可以,但必须搭配GROUP BY,且过滤分组字段(非原始行字段)。
✅ 正确示例:
-- 按专业分组,保留“计算机”专业 SELECT major, COUNT(student_id) AS stu_count FROM student GROUP BY major HAVING major = '计算机';
❌ 错误示例:
-- 错误:无GROUP BY,HAVING过滤原始行 SELECT name, major FROM student HAVING major = '计算机';
6. NULL值的处理
GROUP BY将NULL归为同一组;HAVING过滤NULL需用IS NULL/IS NOT NULL,不可用=或!=。
-- 分组过滤NULL专业组 SELECT major, COUNT(student_id) AS stu_count FROM student GROUP BY major HAVING major IS NOT NULL;
7. 聚合函数别名的使用(数据库差异)
- MySQL:HAVING可直接用SELECT中聚合函数别名;
- Oracle/SQL Server:不可直接用,需重复写聚合函数。
-- MySQL可用 SELECT student_id, AVG(score) AS avg_score FROM score GROUP BY student_id HAVING avg_score > 80; -- 通用写法(所有数据库兼容) SELECT student_id, AVG(score) AS avg_score FROM score GROUP BY student_id HAVING AVG(score) > 80;
总结
- SELECT仅能是GROUP BY分组字段或聚合函数,避免报错;
- WHERE分组前过滤(无聚合函数),HAVING分组后过滤(仅跟GROUP BY);
- 多字段分组细化粒度,NULL归为一组,聚合函数别名需考虑数据库差异。
ps:如果这篇帖子对于还在找工作和找实习的你有所帮助,可以关注我,给本贴点赞、评论、收藏并订阅专栏;同时不要吝啬您的花花
MySQL基础 文章被收录于专栏
《MySQL基础专栏》专为编程新手打造!从SQL核心语法、数据增删改查,到预编译SQL、索引入门、事务基础,层层拆解MySQL必备知识点。专栏摒弃晦涩术语,以通俗讲解+实操案例,带你掌握数据库基础操作,规避SQL注入、性能低效等常见坑,快速搭建MySQL基础体系,轻松应对日常开发中的数据库基础场景。
