基本语法

SELECT 列1, 列2, ..., 聚合函数(列)

FROM 表名

[WHERE 条件]

GROUP BY 分组列

HAVING 分组后条件;

 

HAVING 与 WHERE 的核心区别

 

特性WHERE 子句HAVING 子句
执行时机在分组前过滤数据在分组后过滤数据
可使用聚合函数不可以可以
可使用字段别名不可以可以
操作对象原始表数据分组后的结果集
性能影响先过滤可减少分组数据量对已分组数据做二次过滤


使用场景详解

1. 对聚合结果进行过滤

查询平均身高超过170cm的部门

SELECT 
    dept_id, 
    AVG(height) AS avg_height
FROM students
GROUP BY dept_id
HAVING AVG(height) > 170;


2. 使用字段别名过滤

使用SELECT中定义的别名

SELECT 
    dept_id, 
    COUNT(*) AS student_count
FROM students
GROUP BY dept_id
HAVING student_count > 3;


3. 多条件组合过滤

查询学生数超过2人且平均年龄小于23岁的部门

SELECT 
    dept_id,
    COUNT(*) AS count,
    AVG(age) AS avg_age
FROM students
GROUP BY dept_id
HAVING count > 2 AND avg_age < 23;


实际应用示例

示例1:销售数据分析

 查询总销售额超过10万元的销售员

SELECT 
    salesperson_id,
    SUM(amount) AS total_sales
FROM orders
GROUP BY salesperson_id
HAVING total_sales > 100000;


示例2:学生成绩统计

 查询及格率超过80%的课程

SELECT 
    course_id,
    COUNT(*) AS total,
    SUM(CASE WHEN score >= 60 THEN 1 ELSE 0 END) AS pass_count,
    CONCAT(ROUND(SUM(CASE WHEN score >= 60 THEN 1 ELSE 0 END)/COUNT(*)*100,2),'%') AS pass_rate
FROM exam_results
GROUP BY course_id
HAVING pass_count/total > 0.8;


示例3:用户活跃度分析

 查询月活跃天数超过15天的高活跃用户

SELECT 
    user_id,
    COUNT(DISTINCT DATE(login_time)) AS active_days
FROM user_logins
WHERE YEAR(login_time) = 2023 AND MONTH(login_time) = 6
GROUP BY user_id
HAVING active_days > 15;


性能优化建议

1. 优先使用WHERE过滤:尽可能在WHERE阶段减少数据量,减少分组压力

2. 避免在HAVING中重复计算:

    不推荐

   HAVING COUNT(*)/SUM(amount) > 0.1

  

    推荐

 HAVING ratio > 0.1


3. 合理使用索引:确保GROUP BY和WHERE中的字段有适当索引

 

4. 限制分组数据量:先通过WHERE缩小数据范围再分组

 

常见错误与解决方案

错误类型错误示例正确示例说明
1. WHERE中使用聚合函数SELECT dept_id FROM students WHERE AVG(age) > 20SELECT dept_id FROM students GROUP BY dept_id HAVING AVG(age) > 20WHERE子句不能使用聚合函数,必须使用GROUP BY分组后,用HAVING对分组结果进行过滤
2. 混淆过滤顺序SELECT product_id, COUNT(*) FROM orders GROUP BY product_id HAVING status = 'completed'SELECT product_id, COUNT(*) FROM orders WHERE status = 'completed' GROUP BY product_idHAVING用于过滤分组后的结果,而WHERE用于过滤原始数据。status应该在分组前用WHERE过滤
3. 忽略NULL值影响SELECT dept_id, COUNT(*), COUNT(height) FROM students GROUP BY dept_id HAVING COUNT(*) != COUNT(height)此示例本身是正确的,用于演示NULL值的影响COUNT(*)统计所有行数,COUNT(height)只统计非NULL值。两者不等说明存在NULL值


点赞(2)

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

Dotcpp在线编译      (登录可减少运行等待时间)