CodeGym /课程 /SQL SELF /WHERE 和 HAVING 的对比:执行顺序解析和案例

WHERE 和 HAVING 的对比:执行顺序解析和案例

SQL SELF
第 8 级 , 课程 2
可用

咱们再来梳理一下 SQL 里操作的执行顺序,还有 WHERE 和 HAVING 能干啥、不能干啥。这点很重要,后面很多 SQL 查询的细节都靠它。你得真的搞明白。

那到底 WHEREHAVING 有啥区别,啥时候用哪个,它们怎么配合?搞清楚这个你写查询就不容易绕晕,还能高效过滤数据。来,总结下咱们对 WHEREHAVING 的理解。

啥是 WHERE

WHERE —— 这是个条件,用来在分组或聚合函数之前过滤行。也就是说,先从表里挑出符合条件的行,然后才在剩下的数据上做分组。

👉 想象你在市场上挑水果。WHERE 就像你提前把烂苹果挑掉,还没开始按大小或颜色分组呢。

例子:

SELECT *
FROM students
WHERE age > 18;

这个查询会把所有大于 18 岁的学生选出来,做其他操作之前。

啥是 HAVING

HAVING —— 这是个过滤器,在数据分组(GROUP BY之后用的。它能给分好组的数据加条件,比如只保留平均分大于 80 的学生组。

👉 还是苹果的例子。HAVING 就是你已经把苹果分好篮子(分组)后,现在只关心那些篮子里有十个以上苹果的。

例子:

SELECT 篮子, COUNT(*)
FROM 苹果
GROUP BY 篮子
HAVING COUNT(*) > 10;

这个查询只会选出那些苹果数量大于 10 的篮子。

主要区别:

特点 WHERE HAVING
应用时机 分组前过滤行 分组后过滤组
聚合函数 不能用聚合函数 能用聚合函数
目的 把不需要的行先去掉再分组 把不满足条件的组去掉

WHEREGROUP BYHAVING 的执行顺序

为了更好理解 WHEREHAVING 怎么工作,咱们看看 SQL 查询的执行顺序:

  1. 先执行 FROM,从表里选出行。
  2. 然后用 WHERE,只留下符合条件的行。
  3. 接着用 GROUP BY 分组。得到新的分组数据表。
  4. HAVING,只保留满足条件的组。
  5. 最后选出 SELECT 的结果。

流程图大概这样:

1. FROM → 2. WHERE → 3. GROUP BY → 4. HAVING → 5. SELECT

例子:

SELECT department, AVG(age) AS avg_age
FROM students
WHERE age > 18
GROUP BY department
HAVING AVG(age) > 20;

这里发生了这些事:

  1. students 表里选出 age > 18 的行(用 WHERE)。
  2. 剩下的行按 department 分组。
  3. 每组算出学生的平均年龄。
  4. 平均年龄小于等于 20 的组被 HAVING 排除。
  5. 输出结果。

组合用法的例子

例子 1:分组前后都过滤

条件:找出学生人数大于 5 的院系,只算年龄大于 18 岁的学生。

原始表 students

id name department age gpa
1 Alex Lin ComputerSci 20 3.8
2 Maria Chi Math 22 3.5
3 Anna Song ComputerSci 19 4.0
4 Otto Art Math 17 3.9
5 Liam Park Physics 21 3.7
6 Jane Doe ComputerSci 23 3.6
7 Tom Brown Math 25 3.4
8 Sara White Math 19 3.8
9 John Smith ComputerSci 20 3.7
10 Emily Green Physics 18 3.9
11 Mark Blue ComputerSci 21 3.5
12 Zoe Black Math 22 3.6
13 Max Gray ComputerSci 20 3.9
14 Eva Gold Math 23 3.7
15 Nick Silver Physics 19 3.8

查询:

SELECT department, COUNT(*) AS student_count
FROM students
WHERE age > 18
GROUP BY department
HAVING COUNT(*) > 5;

结果:-- 查询结果

department student_count
ComputerSci 6

解释:

  1. 先删掉 age <= 18 的行(WHERE 条件)。
  2. 按院系分组(GROUP BY department)。
  3. 算每组学生数量。
  4. 把学生数小于等于 5 的组去掉(HAVING COUNT(*) > 5)。

例子 2:用 WHERE 代替 HAVING 的错误

条件:找出平均年龄大于 22 岁的院系。

错误的查询:

SELECT department, AVG(age) AS avg_age
FROM students
WHERE AVG(age) > 22
GROUP BY department;

错误:SQL 不让你在 WHERE 里用聚合函数 AVG,因为这时候聚合还没算出来。

正确的查询:

SELECT department, AVG(age) AS avg_age
FROM students
GROUP BY department
HAVING AVG(age) > 22;

这里 AVG(age) > 22 的条件是在分组后用的。

实用建议

如果你要过滤,用 WHERE。例子:找出工资大于 5000 的所有员工。

SELECT *
FROM employees
WHERE salary > 5000;

如果你要过滤,用 HAVING。例子:找出总工资大于 100000 的部门。

SELECT department, SUM(salary) AS total_salary
FROM employees
GROUP BY department
HAVING SUM(salary) > 100000;

复杂条件可以组合用 WHEREHAVING

例子:找出总人口超过一千万的国家,只算人口超过一百万的城市。

SELECT country, SUM(population) AS total_population
FROM cities
WHERE population > 1000000
GROUP BY country
HAVING SUM(population) > 10000000;

常见错误和解决办法

最常见的错误之一就是把 WHEREHAVING 搞混。比如,试图在 WHERE 里用聚合函数:

SELECT department, COUNT(*)
FROM students
WHERE COUNT(*) > 10
GROUP BY department;

这种查询会报错,因为聚合还没算出来,WHERE 阶段用不了。正确做法是用 HAVING

SELECT department, COUNT(*)
FROM students
GROUP BY department
HAVING COUNT(*) > 10;

还有一种错误是 WHERE 里用错条件。比如:

SELECT department, AVG(age) AS avg_age
FROM students
WHERE avg_age > 20
GROUP BY department;

这里 avg_age > 20 不对,因为 avg_age 还没算出来。解决办法——把条件放到 HAVING

SELECT department, AVG(age) AS avg_age
FROM students
GROUP BY department
HAVING AVG(age) > 20;

希望你现在已经很清楚 WHEREHAVING 的区别、怎么用、怎么避免常见错误。这些知识以后写复杂报表、分析数据、优化查询都超有用。也就是说,绝大多数你要写的 SQL 查询都离不开它们 :)

评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION