【数据库技术】SQL高级查询(分组/排序/聚合函数)

考点频率 :★★★★★(下午题必考,选择题常考,尤其是 WHERE 与 HAVING 的区别)

难度 :⭐⭐⭐⭐

建议:重点掌握 GROUP BY 的用法、HAVING 与 WHERE 的本质区别、聚合函数的正确使用位置

1️⃣ 从"查一条"到"算一组"

上一篇文章我们学了 SELECT 的基本用法------查具体的数据行(比如"查所有年龄大于20岁的学生")。

但在实际业务中,我们经常需要的不只是"列出数据",而是对数据进行汇总统计

  • "每个班有多少人?"
  • "各科的平均分是多少?"
  • "哪个学生的总分最高?"

这些查询不再返回"原始行",而是返回统计结果 。这就需要用到 分组查询(GROUP BY)聚合函数

打个比方 :基本查询就像翻花名册 ,一页一页看。高级查询就像做统计报表------不用看每个人的具体信息,而是问"一共有多少人?""男女比例多少?"。

2️⃣ 聚合函数(复习+补充)

聚合函数对一组值进行计算,返回单个值。上一篇文章已经介绍过,这里快速回顾:

函数 作用 说明
COUNT(*) 统计行数 包含 NULL 行
COUNT(列名) 统计非空值个数 不包含 NULL
SUM(列名) 求和 只适用于数值列
AVG(列名) 求平均值 只适用于数值列
MAX(列名) 求最大值 适用于任意可比较类型
MIN(列名) 求最小值 适用于任意可比较类型

重点 :聚合函数会忽略 NULL 值COUNT(*) 除外)。比如 AVG(成绩) 只计算有成绩的记录,NULL 不参与计算。

3️⃣ GROUP BY------分组聚合

3.1 基本用法

GROUP BY 将表中的数据按某个(或某几个)列进行分组,然后对每个组分别应用聚合函数。

语法

sql 复制代码
SELECT 分组列, 聚合函数(列)
FROM 表名
GROUP BY 分组列;

示例:统计每个班级的人数

sql 复制代码
SELECT 班级号, COUNT(*) AS 人数
FROM 学生表
GROUP BY 班级号;
班级号 人数
101 35
102 32
103 28

3.2 GROUP BY 的核心规则(软考常考)

规则1SELECT 子句中出现的非聚合列 ,必须出现在 GROUP BY 中。

sql 复制代码
-- ✅ 正确:班级号在 GROUP BY 中
SELECT 班级号, AVG(年龄) FROM 学生表 GROUP BY 班级号;

-- ❌ 错误:姓名不在 GROUP BY 中
SELECT 姓名, AVG(年龄) FROM 学生表 GROUP BY 班级号;

原因是:分组后每个组可能有多行,姓名 这个列没有聚合,数据库不知道应该取组里的哪一个姓名,所以报错。

规则2GROUP BY 中可以包含多个列(先按第一列分组,再按第二列分组)。

sql 复制代码
-- 先按班级号分组,再按性别分组
SELECT 班级号, 性别, COUNT(*) AS 人数
FROM 学生表
GROUP BY 班级号, 性别;

3.3 分组前筛选:WHERE(先筛选,再分组)

WHEREGROUP BY 之前 执行,用于先过滤掉不需要的行,再对剩余行进行分组

sql 复制代码
-- 查询年龄大于18岁的学生中,每个班级的人数
SELECT 班级号, COUNT(*) AS 人数
FROM 学生表
WHERE 年龄 > 18
GROUP BY 班级号;

执行顺序 :先 WHERE 筛选年龄>18 → 再 GROUP BY 按班级分组 → 最后 COUNT(*) 统计。

3.4 分组后筛选:HAVING(先分组,再筛选)

HAVINGGROUP BY 之后 执行,用于筛选分组后的结果

sql 复制代码
-- 查询人数大于30的班级
SELECT 班级号, COUNT(*) AS 人数
FROM 学生表
GROUP BY 班级号
HAVING COUNT(*) > 30;

执行顺序 :先 GROUP BY 分组 → 再 COUNT(*) 统计 → 最后 HAVING 筛选人数>30。

3.5 WHERE vs HAVING(核心区别,必考!)

这是软考选择题的高频陷阱题,务必分清:

对比项 WHERE HAVING
执行时机 分组前(先筛选再分组) 分组后(先分组再筛选)
能否使用聚合函数 不能 可以
作用的对象 单个元组(行) 分组后的组
能否使用列别名 ❌ 不能 ✅ 可以(部分DBMS)

一句话记忆WHERE 筛行(分组前),HAVING 筛组(分组后)

sql 复制代码
-- ❌ 错误:WHERE 中不能使用聚合函数
SELECT 班级号, COUNT(*) FROM 学生表 WHERE COUNT(*) > 30 GROUP BY 班级号;

-- ✅ 正确:HAVING 可以使用聚合函数
SELECT 班级号, COUNT(*) FROM 学生表 GROUP BY 班级号 HAVING COUNT(*) > 30;

4️⃣ 分组+排序+筛选的综合示例

完整查询结构

sql 复制代码
SELECT 列名, 聚合函数
FROM 表名
WHERE 行条件        -- 1. 筛选行(分组前)
GROUP BY 列名       -- 2. 分组
HAVING 组条件       -- 3. 筛选组(分组后)
ORDER BY 列名;      -- 4. 排序

示例:查询平均年龄大于19岁的班级,按平均年龄降序排列。

sql 复制代码
SELECT 班级号, AVG(年龄) AS 平均年龄
FROM 学生表
WHERE 性别 = '男'                    -- 只统计男生
GROUP BY 班级号
HAVING AVG(年龄) > 19               -- 平均年龄大于19
ORDER BY 平均年龄 DESC;              -- 从大到小排列

5️⃣ 经典例题

例题1:查询"选课"表中,各门课程的平均成绩,并只显示平均成绩大于80分的课程。

解析

sql 复制代码
SELECT 课程号, AVG(成绩) AS 平均成绩
FROM 选课表
GROUP BY 课程号
HAVING AVG(成绩) > 80;

先按课程号分组,再计算每组的平均成绩,最后筛选平均成绩>80的课程。


例题2:以下 SQL 语句中,正确的是( )。

A. SELECT 班级号, COUNT(*) FROM 学生表 WHERE COUNT(*) > 10 GROUP BY 班级号;

B. SELECT 班级号, AVG(年龄) FROM 学生表 GROUP BY 班级号 HAVING AVG(年龄) > 20;

C. SELECT 班级号, 姓名, COUNT(*) FROM 学生表 GROUP BY 班级号;

D. SELECT 班级号, COUNT(*) FROM 学生表 GROUP BY 班级号 WHERE COUNT(*) > 10;

解析

  • A 错误:WHERE 中不能使用聚合函数。
  • B 正确:HAVING 可以使用聚合函数。
  • C 错误:姓名 不在 GROUP BY 中,却出现在 SELECT 中(非聚合列)。
  • D 错误:WHERE 必须在 GROUP BY 之前。

B


例题3 (判断):HAVING 子句和 WHERE 子句的作用完全相同,可以互换使用。( )

解析 :错误。WHERE 在分组前筛选行,HAVING 在分组后筛选组;WHERE 不能使用聚合函数,HAVING 可以使用。

6️⃣ 执行顺序总结

sql 复制代码
SELECT 班级号, AVG(年龄) AS 平均年龄   -- 第5步:选择列
FROM 学生表                            -- 第1步:确定数据来源
WHERE 性别 = '男'                      -- 第2步:筛选行(不能用聚合函数)
GROUP BY 班级号                        -- 第3步:分组
HAVING AVG(年龄) > 19                  -- 第4步:筛选组(可以用聚合函数)
ORDER BY 平均年龄 DESC;                -- 第6步:排序

7️⃣ 记忆口诀

WHERE 先筛行,GROUP BY 再分组。

聚合函数算统计,HAVING 后筛组。

WHERE 不能有聚合,HAVING 专治聚合条件。

8️⃣ 小测验(评论区对答案)

SQL 语句:SELECT 班级号, COUNT(*) AS 人数 FROM 学生表 GROUP BY 班级号 HAVING 人数 > 30;

请问:这条语句中 人数 这个别名可以在 HAVING 中使用吗?(不同 DBMS 支持情况不同,软考中通常按 SQL 标准判定)

A. 可以,HAVING 中可以使用 SELECT 中定义的别名

B. 不可以,HAVING 中不能使用别名

C. 可以,只要该别名在 SELECT 中定义

D. 取决于 WHERE 子句

🔔 本专栏日更,点击头像 → 专栏《软考中级高频考点》订阅,第一时间接收新内容

#软考中级 #软件设计师 #SQL #GROUP BY #HAVING #聚合函数 #数据库技术基础 #软考备考

相关推荐
DDXYcoder18 分钟前
万字解析动态内存从编译到运行
java·前端·算法
旖旎夜光20 分钟前
【AI入门】大模型介绍全解析:从模型、LLM 到提示词与嵌入
人工智能·笔记·python·学习·ai编程
IvorySQL22 分钟前
PostgreSQL 日报|备用服务器 FSM 数据不一致(9 月 2 日)
服务器·数据库·postgresql
王的宝库31 分钟前
【无标题】
笔记·restful
Capricorn198839 分钟前
科研智能体出现召回率低与数据覆盖冲突怎么排查?知芽 Notebook Skill 机制拆解
大数据·论文阅读·人工智能·笔记
坐吃山猪41 分钟前
【多线程】什么时候必须/推荐使用Thread类
java·开发语言
zcmodeltech44 分钟前
风力发电沙盘模型控制系统设计与灯光联动实现方案——基于STM32与Modbus RTU,服务范围覆盖全国的多场景风力发电沙盘模型定制
网络·数据库·stm32·单片机·嵌入式硬件·能源
tju新生代魔迷1 小时前
Verilog HDL学习笔记(三)| 第3章 基本概念(上)——词法约定与数据类型
笔记·学习
一只小阿乐1 小时前
java 快速上手开发 2
java·开发语言·前端