【数据库技术】SQL嵌套查询(IN/EXISTS/ANY/ALL)

考点频率 :★★★★★(下午题必考,选择题常考,子查询是SQL查询的进阶核心)

难度 :⭐⭐⭐⭐

建议:重点掌握子查询的分类、IN与EXISTS的区别、ANY与ALL与比较运算符的搭配

1️⃣ 什么是嵌套查询?

嵌套查询(子查询,Subquery) 是指在一个 SELECT 语句中嵌套另一个 SELECT 语句 。外层的查询称为外层查询(父查询) ,内层的查询称为子查询

打个比方:你是一个导演,要选一个演员。你先问"哪些人通过了初试?"(子查询),得到一份名单后,再问"名单里谁演过古装剧?"(外层查询)。子查询的结果被外层查询当作"数据源"或"条件值"来使用。

子查询的分类

分类方式 类型 说明
按结果集大小 标量子查询 返回单个值(一行一列)
行子查询 返回一行(多列)
表子查询 返回多行多列(一张表)
按相关性 不相关子查询 子查询独立于外层查询,可单独执行
相关子查询 子查询依赖外层查询的当前行值,不能单独执行

2️⃣ 带 IN 的子查询

IN 用于判断某个值是否在子查询返回的集合中。

语法

sql 复制代码
SELECT 列名 FROM 表名
WHERE 列名 IN (子查询);

示例:查询选修了"数学"课程的学生姓名

sql 复制代码
SELECT 姓名 FROM 学生表
WHERE 学号 IN (
    SELECT 学号 FROM 选课表
    WHERE 课程号 = (SELECT 课程号 FROM 课程表 WHERE 课程名 = '数学')
);

执行逻辑:先执行最内层子查询得到"数学"的课程号,再执行中层子查询得到选修了该课程的所有学号,最后外层查询筛选出这些学号对应的学生姓名。

NOT IN 表示不在集合中。

示例:查询没有选修任何课程的学生姓名

sql 复制代码
SELECT 姓名 FROM 学生表
WHERE 学号 NOT IN (
    SELECT DISTINCT 学号 FROM 选课表
);

3️⃣ 带 EXISTS 的子查询

EXISTS 用于判断子查询是否返回了至少一行数据。它只关注"有没有数据",不关心具体返回什么。

语法

sql 复制代码
SELECT 列名 FROM 表名
WHERE EXISTS (子查询);

示例:查询选修了"数学"课程的学生姓名(用 EXISTS 实现)

sql 复制代码
SELECT 姓名 FROM 学生表 S
WHERE EXISTS (
    SELECT * FROM 选课表 SC
    WHERE SC.学号 = S.学号
    AND SC.课程号 = (SELECT 课程号 FROM 课程表 WHERE 课程名 = '数学')
);

注意 :子查询中的 SELECT *惯用写法 ,因为 EXISTS 只判断存在性,不关心具体列。写成 SELECT 1SELECT * 效果一样。

执行逻辑:对于外层查询的每一行,执行子查询检查是否存在满足条件的记录。如果子查询返回至少一行,EXISTS 为真,该行被包含在结果中。

4️⃣ IN vs EXISTS(核心区别,必考!)

这是软考选择题的高频考点

对比项 IN EXISTS
子查询类型 不相关子查询(优先执行子查询,得到完整结果集) 相关子查询(通常与外层查询关联)
判断依据 判断值是否在子查询结果集合中 判断子查询是否有返回行(存在性)
子查询结果集 需要完整结果集(执行完所有子查询) 找到第一行匹配即停止(短路求值)
处理NULL IN 遇到 NULL 可能导致整个结果为空 EXISTS 不受 NULL 影响(只关心行存在性)
外层查询数据量大时 子查询结果集小则效率高 外层每行都要执行子查询,可能较慢
子查询数据量大时 子查询结果集大则效率低 利用索引匹配时效率高
SELECT 子句 必须返回一列(用于比较) 可以是任意列(通常写 *1

选择建议

  • 子查询结果集较小 (外层表大)→ 用 IN(先执行子查询,得到结果集,再与外层匹配)
  • 子查询结果集较大 (内层表大)→ 用 EXISTS(找到匹配即停止,利用索引)
  • 需要关联外层表 的查询 → 只能用 EXISTSIN 的子查询不能直接引用外层表的列)

5️⃣ 带 ANY / ALL 的子查询

ANYALL比较运算符=><>=<=<>)结合使用,用于将某个值与子查询返回的一组值进行比较。

运算符 含义 相当于
= ANY 等于子查询结果中的任意一个 等价于 IN
> ANY 大于 子查询结果中的最小值 比最小的还大
< ANY 小于 子查询结果中的最大值 比最大的还小
> ALL 大于 子查询结果中的最大值 比最大的还大
< ALL 小于 子查询结果中的最小值 比最小的还小
<> ANY 不等于子查询结果中的任意一个 不等于某个值(几乎无意义)
<> ALL 不等于子查询结果中的全部 等价于 NOT IN

示例

sql 复制代码
-- 查询成绩高于"所有"学生平均成绩的学生
SELECT * FROM 选课表
WHERE 成绩 > ALL (SELECT AVG(成绩) FROM 选课表 GROUP BY 学号);
-- 实际上这样写有问题:ALL后面应该跟一个单列集合,子查询返回多个平均值后,> ALL表示大于其中最大的那个

更准确的示例

sql 复制代码
-- 查询比"所有"计算机系学生年龄都大的学生
SELECT * FROM 学生表
WHERE 年龄 > ALL (SELECT 年龄 FROM 学生表 WHERE 系别 = '计算机系');

含义:年龄 > 计算机系所有人中的最大年龄 → 比计算机系最年长的还年长。

sql 复制代码
-- 查询比"至少一个"计算机系学生年龄大的学生(即比计算机系最年轻的人还大)
SELECT * FROM 学生表
WHERE 年龄 > ANY (SELECT 年龄 FROM 学生表 WHERE 系别 = '计算机系');

含义:年龄 > 计算机系至少一个人的年龄 → 比计算机系最年轻的还年长。

6️⃣ 相关子查询 vs 不相关子查询

对比项 不相关子查询 相关子查询
独立性 子查询可以独立执行,不依赖外层 子查询依赖外层的当前行值
执行次数 子查询执行一次 子查询执行多次(外层每行一次)
典型用法 子查询返回一个固定集合,外层用 IN/= 判断 子查询中使用外层表的列作为条件,用 EXISTS
性能 通常较快 可能较慢(每次都要执行子查询)

7️⃣ 经典例题

例题1:用 SQL 查询"选修了所有课程"的学生学号。

解析 :这是一个典型的"所有"查询,用 NOT EXISTS 实现双否定。

sql 复制代码
SELECT 学号 FROM 学生表 S
WHERE NOT EXISTS (
    SELECT * FROM 课程表 C
    WHERE NOT EXISTS (
        SELECT * FROM 选课表 SC
        WHERE SC.学号 = S.学号 AND SC.课程号 = C.课程号
    )
);

逻辑:不存在任何一门课程,该学生没选。即"所有课程都选了"。


例题2 :以下 SQL 语句中,= ANY 等价于( )。

A. IN

B. NOT IN

C. EXISTS

D. NOT EXISTS

解析= ANY 表示等于子查询结果中的任意一个值,等价于 IN。选 A


例题3 (判断):EXISTS 子查询中,SELECT 子句可以写任意列,因为 EXISTS 只判断是否有返回行,不关心具体值。( )

解析 :正确。EXISTS 只关心子查询是否返回了数据行,不关心具体列值,因此 SELECT *SELECT 1SELECT 学号 效果相同。

8️⃣ 记忆口诀

IN 在集合中,EXISTS 有没有行。

= ANY 就是 IN<> ALL 就是 NOT IN

> ANY 大于最小,> ALL 大于最大。

< ANY 小于最大,< ALL 小于最小。

EXISTS 相关子查询口诀

外层每行查一次,关联条件要写对。

NOT EXISTS 套两层,就是"全选"反过来。

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

SQL 语句:SELECT 姓名 FROM 学生表 WHERE 年龄 > ANY (SELECT 年龄 FROM 学生表 WHERE 系别 = '计算机系')

该语句的含义是( )。

A. 查询比所有计算机系学生年龄都大的学生

B. 查询比至少一个计算机系学生年龄大的学生

C. 查询年龄和计算机系学生都不同的学生

D. 查询年龄大于计算机系学生平均年龄的学生

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

#软考中级 #软件设计师 #SQL #嵌套查询 #IN #EXISTS #ANY #ALL #数据库技术基础 #软考备考

相关推荐
清晨00142 分钟前
国产化数据库替代方案:openGauss 详解与 MySQL 平滑迁移实战
数据库·mysql
λqaq71 小时前
MongoDB数据库基础 :非关系型数据库入门与常用操作
数据库·学习·mongodb·nosql
词却1 小时前
数据库基础:TCL事务与DDL视图
数据库
码农小麦1 小时前
LangChain 1.3.18 + DeepSeek-v4-flash 工具调用踩坑实录
网络·数据库·langchain
凯尔萨厮1 小时前
Java学习笔记十四(网络通信)
笔记·学习
FfHUCisI1 小时前
Golang 切片扩容策略
开发语言·数据库·golang
en.en..1 小时前
Ubuntu嵌入式开发 export环境变量
java·开发语言·数据库
攻城有术1 小时前
专项攻克——重写 Redis 依赖包方法的 6 种实现方式
java·数据库·redis·bootstrap
IvorySQL1 小时前
基于 PostgreSQL 的非线性回归原理与 AI 数据库融合实践
数据库·人工智能·postgresql