SQL:子查询(subqueries)

目录

[🎯 从问题出发:为什么我们需要子查询?](#🎯 从问题出发:为什么我们需要子查询?)

[🔍 子查询本质:查中间结果](#🔍 子查询本质:查中间结果)

[📚 子查询的分类](#📚 子查询的分类)

[✅ 非相关子查询(Non-correlated Subquery)](#✅ 非相关子查询(Non-correlated Subquery))

[🔄 相关子查询(Correlated Subquery)](#🔄 相关子查询(Correlated Subquery))

[相关 vs 非相关子查询](#相关 vs 非相关子查询)

一句话总结:


🎯 从问题出发:为什么我们需要子查询?

假设你有一个"学生表" students,像这样:

id name age score
1 小明 18 90
2 小红 17 95
3 小刚 18 87

你想问这样一个问题:

"谁的分数是全班最高的?"

第一性思维问自己:我们需要两个信息:

  1. 最高分是多少?(最大值)

  2. 哪个学生的分数是这个最大值?

你发现:这不是一步能查到的。

你得先"查一个中间结果",再用这个结果查最终的目标。

🔍 子查询本质:查中间结果

定义:

子查询(subquery)就是一个嵌套在 SQL 里的"小查询",用来提前计算出你需要的"中间值",再交给外层的大查询使用。

就像数学题里你先算出 x = 5,再把这个 x 代入下一个步骤一样。

📚 子查询的分类

按"是否依赖外层查询"

✅ 非相关子查询(Non-correlated Subquery)

定义:这个子查询完全可以单独运行,不依赖外层查询的数据。

sql 复制代码
SELECT ...
FROM ...
WHERE 某列 [操作符] (子查询);

子查询:

sql 复制代码
(SELECT ... FROM ... WHERE ...)

特点:

  • 子查询放在圆括号里;

  • 通常出现在 WHEREFROMSELECT 语句中;

  • 可以先执行,执行完再带入主查询。

1️⃣ 用在 WHERE 条件里

比如:查出分数等于全班最高分的学生

sql 复制代码
SELECT name
FROM students
WHERE score = (SELECT MAX(score) FROM students);

子查询结果是一个"标量"(single value),主查询用它来比较筛选。

2️⃣ 用在 FROM 子句中(表子查询)

把子查询当作一个临时表(derived table)来看待,用来做进一步的查询

sql 复制代码
SELECT *
FROM (SELECT * FROM students WHERE score > 90) AS top_students;

这个例子中:

  • 子查询选出成绩大于 90 的人;

  • 外层查询可以对它排序、分页、分组等等。

本质:把子查询变成一张临时表使用。

注意:每当你在子查询中创建了一个临时表,你必须用别名参考该表。在该例中,我们为这个临时表命名为top_students;

3️⃣ 用在 SELECT 中(计算列)

为每一行额外查询一个值(但子查询结果是固定的,不会根据外层变)

sql 复制代码
SELECT name, score,
  (SELECT AVG(score) FROM students) AS avg_score
FROM students;
  • 每一行都显示学生自己的成绩,以及"全班平均分"

  • 这个 AVG(score) 是一次性执行的,和外层无关

注意事项

子查询必须返回"合适的结果数量"

比如:

  • 如果你写 = (SELECT ...),就必须保证子查询只返回一行一列

  • 如果子查询返回多行,用 INEXISTS


🔄 相关子查询(Correlated Subquery)

定义:子查询不能单独运行,它的执行依赖于外层每一行的内容。

sql 复制代码
SELECT ...
FROM 表A a
WHERE 某条件操作符 (
  SELECT ...
  FROM 表B b
  WHERE b.列 = a.列
);

⚙️ 执行过程:

  1. 外层取出第一行(如 a1

  2. 子查询执行一遍,带入 a1 的值

  3. 判断是否满足条件

  4. 重复步骤 1~3,直到遍历所有外层行

和循环查差不多,但由数据库优化器控制流程。

1️⃣ 用在 WHERE 子句里

找出分数比自己同龄人平均分高的学生:

sql 复制代码
SELECT name, age, score
FROM students s1
WHERE score > (
  SELECT AVG(score)
  FROM students s2
  WHERE s2.age = s1.age
);
  • 子查询里的 s1.age 就来自外层;

  • 所以每个年龄段单独算平均分再比较。

2️⃣ 用在 SELECT 字段中(作为计算列)

给每个学生显示"自己年级的平均分":

sql 复制代码
SELECT name, age, score,
  (SELECT AVG(score) FROM students s2 WHERE s2.age = s1.age) AS avg_score
FROM students s1;
  • 外层是每个学生;

  • 内层是"拿着你的年龄,查出平均分";

  • 每一行都有自己"定制的"子查询结果。

3️⃣ 用在 EXISTS 判断中

找出有"重名"的学生:

sql 复制代码
SELECT name
FROM students s1
WHERE EXISTS (
  SELECT 1
  FROM students s2
  WHERE s1.name = s2.name AND s1.id <> s2.id
);
  • EXISTS 判断子查询是否返回值;

  • 子查询中引用了外层的 s1.name

  • 所以是相关子查询。

相关 vs 非相关子查询

项目 非相关子查询 相关子查询
是否依赖外层数据 ❌ 不依赖 ✅ 依赖
能否单独执行 ✅ 可以 ❌ 不行
执行次数 1 次 多次(每行一次)
使用场景 全局计算 / 固定值 动态对比 / 局部判断
性能 较高 较低(需优化)

一句话总结:

子查询(Subquery)就是 SQL 中处理"复杂逻辑拆成两步"的工具,像数学里的中间变量,能帮助你更自然地表达"先求出一个值,再用它继续筛选"的需求。

相关推荐
heartbeat..4 小时前
Spring AOP 全面详解(通俗易懂 + 核心知识点 + 完整案例)
java·数据库·spring·aop
麦聪聊数据6 小时前
MySQL并发与锁:从“防止超卖”到排查“死锁”
数据库·sql·mysql
AC赳赳老秦7 小时前
DeepSeek 私有化部署避坑指南:敏感数据本地化处理与合规性检测详解
大数据·开发语言·数据库·人工智能·自动化·php·deepseek
YMatrix 官方技术社区8 小时前
YMatrix 存储引擎解密:MARS3 存储引擎如何超越传统行存、列存实现“时序+分析“场景性能大幅提升?
开发语言·数据库·时序数据库·数据库架构·智慧工厂·存储引擎·ymatrix
辞砚技术录9 小时前
MySQL面试题——索引2nd
数据库·mysql·面试
linweidong9 小时前
C++thread pool(线程池)设计应关注哪些扩展性问题?
java·数据库·c++
欧亚学术10 小时前
突发!刚刚新增17本期刊被剔除!
数据库·论文·sci·期刊·博士·scopus·发表
黑白极客10 小时前
怎么给字符串字段加索引?日志系统 一条更新语句是怎么执行的
java·数据库·sql·mysql·引擎
大厂技术总监下海11 小时前
数据湖加速、实时数仓、统一查询层:Apache Doris 如何成为现代数据架构的“高性能中枢”?
大数据·数据库·算法·apache
LeenixP11 小时前
RK3576-Debian12删除userdata分区
linux·运维·服务器·数据库·debian·开发板