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;

总结

  1. SELECT仅能是GROUP BY分组字段或聚合函数,避免报错;
  2. WHERE分组前过滤(无聚合函数),HAVING分组后过滤(仅跟GROUP BY);
  3. 多字段分组细化粒度,NULL归为一组,聚合函数别名需考虑数据库差异。

ps:如果这篇帖子对于还在找工作和找实习的你有所帮助,可以关注我,给本贴点赞、评论、收藏并订阅专栏;同时不要吝啬您的花花

MySQL基础 文章被收录于专栏

《MySQL基础专栏》专为编程新手打造!从SQL核心语法、数据增删改查,到预编译SQL、索引入门、事务基础,层层拆解MySQL必备知识点。专栏摒弃晦涩术语,以通俗讲解+实操案例,带你掌握数据库基础操作,规避SQL注入、性能低效等常见坑,快速搭建MySQL基础体系,轻松应对日常开发中的数据库基础场景。

全部评论

相关推荐

今天 01:40
已编辑
武汉理工大学 Java
点赞 评论 收藏
分享
评论
1
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务