CodeGym /课程 /SQL SELF /用 HAVING 过滤聚合数据

用 HAVING 过滤聚合数据

SQL SELF
第 8 级 , 课程 1
可用

我们还没聊过的一个点,就是怎么在用聚合函数之后过滤分组?有时候我们不需要所有学院——只想看学生人数超过一百的那些。或者只关心平均工资高于 50,000 的部门。今天我们就来认识下怎么用 HAVING 过滤聚合后的数据。

既然有 WHERE,为啥还要 HAVING?直接在 GROUP BY 后面加 WHERE 不行吗 :)

没那么简单!首先,SQL 里的操作符顺序是固定的,WHERE 是在 GROUP BY 之前执行的。

那能不能把 WHERE 放到 GROUP BY 后面?

也不行!其实很多时候我们需要在分组前先过滤一波数据,然后再分组,最后再把分组后的结果再过滤一遍。

那是不是可以直接复制 WHERE,改个名字叫 HAVING,放在 GROUP BY 后面?

对,就是这么干的!:)

HAVINGWHERE 的区别

WHERE 是在分组前过滤行。

想象下你挑蛋糕吃:草莓味和巧克力味的留下,其他的都不要。这就是 WHERE 的活儿。

HAVING 是在数据分组和聚合函数“施法”之后过滤。

比如你已经把蛋糕按桌子分组,数好了每桌有几个蛋糕,现在只想看蛋糕数大于三的桌子。

所以,HAVING 是用来在分组层面过滤数据的。

HAVING 的语法

语法和 WHERE 差不多,但用法有点不一样:

SELECT 列, 聚合函数
FROM 表
GROUP BY 列
HAVING 条件;

执行步骤:

  1. 先用 WHERE 过滤行。
  2. 然后用 GROUP BY 分组。
  3. 对分组结果用聚合函数处理。
  4. 最后用 HAVING 过滤分组结果。

HAVING 的用法例子

例子 1:筛选学生人数多的学院

你想知道大学里哪些学院学生人数超过 100。假设有张 students 表:

id name faculty
1 Alice Engineering
2 Bob Engineering
3 Charlie Arts
4 Daisy Business
5 ... ...

查询:

SELECT faculty, COUNT(*) AS student_count
FROM students
GROUP BY faculty
HAVING COUNT(*) > 100;

这里发生了什么:

  • 先用 GROUP BYfaculty 分组。
  • 然后 COUNT(*) 统计每个学院的学生数。
  • 最后 HAVING 把学生数小于等于 100 的学院都过滤掉。

结果:

faculty student_count
Engineering 150
Arts 120

例子 2:平均工资高的部门

你想找出平均工资超过 50,000 的部门。假设有张 employees 表:

id name department salary
1 Alice IT 60000
2 Bob HR 45000
3 Charlie IT 70000
4 Daisy HR 52000
5 ... ... ...

查询:

SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING AVG(salary) > 50000;

结果:

department avg_salary
IT 65000

注意:HAVING 是在 GROUP BY 之后处理聚合结果的。

WHEREGROUP BYHAVING 的执行顺序

WHEREHAVING 的过滤是在不同阶段。为了更清楚地理解区别,来看下 SQL 查询的分步流程:

  1. WHERE:过滤行。

    这一步处理表里的所有行。不满足 WHERE 条件的行直接被丢弃,不会进入后续处理。

  2. GROUP BY:分组。

    过滤后的行会根据 GROUP BY 指定的列分组。

  3. 聚合函数:

    对分组后的数据用 COUNT()AVG()SUM() 等聚合函数处理。

  4. HAVING:过滤分组。

    这一步只处理聚合结果。HAVING 的条件只对分组起作用。

HAVING 的特点

特点 1:能用聚合函数

HAVINGWHERE 最大的区别就是能用聚合函数。比如:

SELECT department, AVG(salary)
FROM employees
GROUP BY department
HAVING AVG(salary) > 50000;

在这个查询里,AVG(salary) 不能写在 WHERE 里,因为 WHERE 是在分组前处理的。像这样写:

SELECT department, AVG(salary)
FROM employees
WHERE AVG(salary) > 50000
GROUP BY department;

会报错:aggregate functions are not allowed in WHERE

特点 2:没分组也能用 HAVING

你甚至可以不用 GROUP BY,直接用 HAVING。这种情况下,所有记录会被当成一个分组:

SELECT AVG(salary) AS avg_salary
FROM employees
HAVING AVG(salary) > 50000;

实战例子

假设有家商店,有张销售表 sales

id product_id sales_amount
1 101 200.00
2 102 300.00
3 101 400.00
4 103 150.00

查询:找出总销售额大于 500 的商品。

SELECT product_id, SUM(sales_amount) AS total_sales
FROM sales
GROUP BY product_id
HAVING SUM(sales_amount) > 500;

结果:

product_id total_sales
101 600.00

常见错误

WHERE 里用聚合函数:

比如:

SELECT department, AVG(salary)
FROM employees
WHERE AVG(salary) > 50000
GROUP BY department;

错误:WHERE 里不能用聚合函数。

NULL 有关的错误:

如果数据里有 NULL,过滤结果可能会很奇怪。比如:

SELECT department, SUM(salary)
FROM employees
GROUP BY department
HAVING SUM(salary) > 0;

如果 salary 这一列全是 NULL,结果可能是 0 或者空的。

恭喜你!现在你已经可以很自信地过滤聚合数据啦!记住,HAVING 是你做分组分析的利器,普通 WHERE 搞不定的场景就靠它了。

2
任务
SQL SELF, 第 8 级, 课程 1
已锁定
按院系筛选学生数量大于2的情况
按院系筛选学生数量大于2的情况
2
任务
SQL SELF, 第 8 级, 课程 1
已锁定
按总销售额过滤产品
按总销售额过滤产品
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION