一家在线教育平台有两张表:students 和 courses。
students 表记录了学生的基本信息以及他们报名的课程。courses 表记录了课程的详细信息,包括课程的难度等级。现在需要找出报名了至少两门课程的学生,并列出他们的姓名以及报名的课程数量。
studentsstudent_id | name | course_id |
|---|---|---|
1 | Alice | 101 |
2 | Bob | 102 |
3 | Alice | 103 |
4 | Charlie | 104 |
5 | Alice | 105 |
6 | Bob | 106 |
coursescourse_id | course_name | difficulty |
|---|---|---|
101 | Mathematics | Medium |
102 | Physics | Hard |
103 | Chemistry | Medium |
104 | Biology | Easy |
105 | Computer Science | Hard |
106 | English | Easy |
找出报名了至少两门课程的学生,并列出他们的姓名以及报名的课程数量。
SELECT
s.name,
COUNT(DISTINCT s.course_id) AS course_count
FROM
students s
GROUP BY
s.name
HAVING
COUNT(DISTINCT s.course_id) >= 2;根据示例数据,执行上述SQL语句后,结果如下:
name | course_count |
|---|---|
Alice | 3 |
Bob | 2 |
HAVING 的基本语法HAVING 通常与 GROUP BY 一起使用,其语法结构如下:
sql复制
SELECT column1, column2, AGG_FUNC(column3) AS alias
FROM table_name
GROUP BY column1, column2
HAVING condition;GROUP BY:将数据按指定列分组。HAVING:对分组后的结果进行筛选,筛选条件可以包含聚合函数(如 COUNT、SUM、AVG 等)。HAVING 的作用HAVING 的主要作用是筛选满足特定条件的分组。它与 WHERE 的区别在于:
WHERE:在分组之前筛选行,不能使用聚合函数。HAVING:在分组之后筛选分组,可以使用聚合函数。假设我们有一个 students 表,记录学生的姓名和选修的课程编号:
name | course_id |
|---|---|
Alice | 1 |
Alice | 2 |
Bob | 3 |
Charlie | 4 |
Charlie | 5 |
Charlie | 6 |
GROUP BY**):- 按照学生的姓名分组,每个学生是一个独立的分组。- 分组后,每个分组的数据如下: - Alice:[1, 2] - Bob:[3] - Charlie:[4, 5, 6]COUNT(DISTINCT course_id)**):- 对每个分组计算选修的不同课程数量: - Alice:2 - Bob:1 - Charlie:3HAVING**):- 使用 `HAVING COUNT(DISTINCT course_id) >= 2` 筛选出课程数量大于等于 2 的分组。- 结果: - Alice:2 - Charlie:3最终的 SQL 查询如下:
sql复制
SELECT
name,
COUNT(DISTINCT course_id) AS course_count
FROM
students
GROUP BY
name
HAVING
COUNT(DISTINCT course_id) >= 2;HAVING 的关键点HAVING 条件中可以使用聚合函数(如 COUNT、SUM、AVG 等),而 WHERE 条件中不能使用聚合函数。HAVING 是在分组之后对分组结果进行筛选,而 WHERE 是在分组之前对行进行筛选。HAVING 可以结合多个聚合函数进行复杂的筛选条件。假设需求是“找出选修了至少两门不同课程的学生”,以下两种写法的区别:
HAVINGsql复制
SELECT
name,
COUNT(DISTINCT course_id) AS course_count
FROM
students
GROUP BY
name
HAVING
COUNT(DISTINCT course_id) >= 2;WHERE 写法sql复制
SELECT
name,
COUNT(DISTINCT course_id) AS course_count
FROM
students
WHERE
COUNT(DISTINCT course_id) >= 2 -- 错误:WHERE 不能使用聚合函数
GROUP BY
name;WHERE 不能使用聚合函数。HAVING 是在分组后对分组结果进行筛选,通常与聚合函数配合使用。WHERE 是在分组前对行进行筛选,不能使用聚合函数。HAVING。HAVING 和 WHERE 是 SQL 中用于数据筛选的两个重要的子句,但它们在作用范围、使用场景和语法上有明显的区别。以下是它们的主要区别:
WHERE:- **作用对象**:`WHERE` 是在分组(`GROUP BY`)之前对**单行数据**进行筛选。- **筛选时机**:在数据分组之前,逐行判断是否满足条件。- **使用场景**:用于筛选表中的行,不能使用聚合函数(如 `COUNT`、`SUM` 等)。HAVING:- **作用对象**:`HAVING` 是在分组(`GROUP BY`)之后对**分组结果**进行筛选。- **筛选时机**:在数据分组并计算聚合函数之后,对分组进行筛选。- **使用场景**:用于筛选分组后的结果,可以使用聚合函数。WHERE:- **不支持聚合函数**:`WHERE` 子句中不能使用聚合函数(如 `COUNT`、`SUM`、`AVG` 等),因为这些函数需要在分组之后才有意义。- **示例**: sql复制
SELECT name, COUNT(course_id) AS course_count FROM students WHERE COUNT(course_id) >= 2; -- 错误:WHERE 不能使用聚合函数
HAVING:- **支持聚合函数**:`HAVING` 子句中可以使用聚合函数,因为它是对分组后的结果进行筛选。- **示例**: sql复制
SELECT name, COUNT(course_id) AS course_count FROM students GROUP BY name HAVING COUNT(course_id) >= 2; -- 正确:HAVING 可以使用聚合函数
WHERE:- **行级筛选**:用于在分组之前筛选出符合条件的行。- **示例**: sql复制
SELECT name, course_id FROM students WHERE course_id > 10; -- 筛选出课程编号大于10的行
HAVING:- **分组级筛选**:用于在分组之后筛选出符合条件的分组。- **示例**: sql复制
SELECT name, COUNT(course_id) AS course_count FROM students GROUP BY name HAVING COUNT(course_id) >= 2; -- 筛选出选修了至少两门课程的学生
SQL 查询的执行顺序如下:
FROM:确定数据来源表。WHERE:在分组之前筛选行。GROUP BY:对筛选后的数据进行分组。HAVING:在分组之后筛选分组。SELECT:选择需要的列并返回结果。WHERE:- 作用于单行数据。- 不能使用聚合函数。- 用于在分组之前筛选行。HAVING:- 作用于分组后的结果。- 可以使用聚合函数。- 用于在分组之后筛选分组。案例二
SELECT
COUNT(*) AS first_name_count, -- 统计每个姓氏的出现次数
CASE
WHEN code LIKE '王%' THEN '王'
WHEN code LIKE '邓%' THEN '邓'
ELSE '其他' -- 添加 ELSE 部分,避免未匹配的情况
END AS code_first_name,
level
FROM
dma.dma_dop_dim_project_manager
GROUP BY
code_first_name, level -- 按姓氏和 level 分组
HAVING
COUNT(*) > 10; -- 筛选出姓氏出现次数大于10的分组CASE 语句的:- 将 `CASE` 语句的逻辑分支正确嵌套,并添加了 `ELSE '其他'`,以避免未匹配的情况。- 修正了 `CASE` 语句的语法错误,确保每个分支以 `THEN` 结束,并在最后以 `END` 结束。- 将 `COUNT(code_first_name)` 改为 `COUNT(*)`,并命名为 `first_name_count`,避免与 `CASE` 表达式的结果列名冲突。GROUP BY 的修正:- `GROUP BY` 中使用了 `CASE` 表达式的结果列 `code_first_name` 和 `level`,确保分组逻辑正确。HAVING 的修正:- `HAVING` 子句中使用了 `COUNT(*) > 10`,筛选出姓氏出现次数大于 10 的分组。code 不属于“王”或“邓”,则归类为“其他”。level,并筛选出满足条件的分组。原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。