当前位置: 首页 > news >正文

子查询及其分类

目录

      • 1.概念
      • 2.例子
      • 一、例子:
        • 1. 标量子查询(返回 1 行 1 列,常作 “单一条件值”)
        • 2. 列子查询(返回 1 列多行,常配`IN`/`ANY`/`ALL`)
        • 3. 行子查询(返回 1 行多列,常作 “多字段匹配条件”)
        • 4. 表子查询(返回多行多列,常作 “临时表” 供主查询调用)
      • 二、按在主查询中的位置分类(补充场景)
        • 1. WHERE 子句中的子查询(前面已覆盖,再补 1 个业务例)
        • 2. FROM 子句中的子查询(即表子查询,再补 1 个复杂例)
        • 3. SELECT 子句中的子查询(每行数据对应 1 个计算值)
      • 关键总结
      • sql语句的执行顺序:

1.概念

子查询是嵌套在其他 SQL 查询(如 SELECTINSERTUPDATEDELETE 语句)中的查询。它可以将一个查询的结果作为另一个查询的条件或数据来源,能让复杂的查询需求通过分步、嵌套的方式实现。

子查询主要有以下几类:

  • 按返回结果行数分类:
    • 标量子查询:返回单一值(一行一列),可用于 WHERE 子句中与某个值进行比较,比如 SELECT * FROM student WHERE age > (SELECT AVG(age) FROM student);,这里子查询返回学生年龄的平均值,主查询筛选出年龄大于该平均值的学生。
    • 列子查询:返回单列多行的数据,常与 INANYALL 等操作符一起使用,例如 SELECT * FROM student WHERE class_id IN (SELECT id FROM class WHERE grade = '高三');,子查询返回高三班级的 id 列(多行),主查询筛选出班级 id 在这些 id 中的学生。
    • 行子查询:返回单行多列的数据,可用于与一行数据进行比较,比如 SELECT * FROM student WHERE (age, score) = (SELECT age, score FROM student WHERE name = '张三');,子查询返回张三的年龄和分数(一行两列),主查询筛选出年龄和分数与之相同的学生。
    • 表子查询:返回多行多列的数据,可作为 FROM 子句中的数据源(通常需要给子查询取别名),例如 SELECT t.name, t.avg_score FROM (SELECT name, AVG(score) AS avg_score FROM student GROUP BY name) AS t WHERE t.avg_score > 80;,子查询返回每个学生的姓名和平均分数(多行多列),主查询再筛选出平均分数大于 80 的学生姓名和平均分数。
  • 按在主查询中的位置分类:
    • WHERE 子句中的子查询:如前面提到的标量子查询、列子查询等,用子查询结果作为 WHERE 子句的条件。
    • FROM 子句中的子查询:即表子查询,将子查询结果当作一张临时表供主查询 FROM 子句使用。
    • SELECT 子句中的子查询:子查询位于 SELECT 子句中,用于为每行数据生成一个计算值,例如 SELECT name, (SELECT AVG(score) FROM student) AS all_avg_score FROM student;,子查询返回所有学生的平均分数,主查询为每个学生显示姓名和这个总平均分数。

2.例子

一、例子:

先明确基础表结构(方便理解例子):

表名关键字段
students学生 ID (sid)、姓名 (sname)、年龄 (age)、班级 ID (cid)
scores成绩 ID (scid)、学生 ID (sid)、科目 (subject)、分数 (score)
classes班级 ID (cid)、班级名称 (cname)(如 “高三 1 班”)
1. 标量子查询(返回 1 行 1 列,常作 “单一条件值”)

业务场景:查询 “年龄大于全校平均年龄” 的学生姓名和年龄
(子查询先算 “全校平均年龄”,主查询用这个值当筛选条件)

SELECT sname, age
FROM students
-- 子查询返回“单一数值”(如平均年龄17.5),用>、<等符号比较
WHERE age > (SELECT AVG(age)  -- 子查询:计算所有学生的平均年龄(1行1列)FROM students
);

结果示例:只显示年龄超过 17.5 的学生,比如(李四,18)、(王五,19)。

2. 列子查询(返回 1 列多行,常配IN/ANY/ALL

业务场景:查询 “在‘高三班级’中的所有学生姓名和班级 ID”
(子查询先找 “所有高三班级的 ID”,主查询筛选学生的班级 ID 在这个范围内)

SELECT sname, cid
FROM students
-- 子查询返回“多个班级ID”(如1、2),用IN判断“是否在其中”
WHERE cid IN (SELECT cid  -- 子查询:找出所有班级名称含“高三”的班级ID(1列多行)FROM classesWHERE cname LIKE '高三%'  -- 匹配“高三1班”“高三2班”等
);

结果示例:只显示属于高三班级的学生,比如(张三,1)、(李四,2)。

3. 行子查询(返回 1 行多列,常作 “多字段匹配条件”)

业务场景:查询 “与‘张三’年龄和班级都相同” 的学生(含张三本人)
(子查询先找 “张三的年龄和班级 ID”,主查询用这两个值同时匹配)

SELECT sname, age, cid
FROM students
-- 子查询返回“1行2列”(如张三的年龄18、班级ID1),用=匹配多字段
WHERE (age, cid) = (SELECT age, cid  -- 子查询:获取“张三”的年龄和班级ID(1行2列)FROM studentsWHERE sname = '张三'  -- 确保子查询只返回1行(张三只有1个)
);

结果示例:显示所有 “年龄 18 且班级 ID1” 的学生,比如(张三,18,1)、(赵六,18,1)。

4. 表子查询(返回多行多列,常作 “临时表” 供主查询调用)

业务场景:查询 “平均分数大于 80 分的学生姓名和其平均分数”
(子查询先算 “每个学生的平均分数”,主查询再筛选平均分数 > 80 的记录)

-- 子查询作为“临时表t”,必须给临时表取别名(这里叫t)
SELECT t.sname, t.avg_sc
FROM (-- 子查询:计算每个学生的平均分数(多行多列:学生姓名、平均分数)SELECT s.sname, AVG(sc.score) AS avg_scFROM students sJOIN scores sc ON s.sid = sc.sid  -- 关联学生表和成绩表GROUP BY s.sid, s.sname  -- 按学生分组,算每个学生的平均分
) AS t  -- 给子查询的临时表取名t
WHERE t.avg_sc > 80;  -- 主查询:筛选临时表中平均分数>80的记录select s.name ,avg(score )  from sinner join  (select sid, avg(score )  from sc  group by sid  having  avg(score)>80 ) t on t.sid =s.id-- 这个一次出结果
select s.sid, s.sname,avg(score)  from s inner join sc  on  s.id=sc.sid group by  s.sid,s.sname  having avg(score) >8 0;         

结果示例:只显示平均分超 80 的学生,比如(张三,85)、(王五,82)。

二、按在主查询中的位置分类(补充场景)

1. WHERE 子句中的子查询(前面已覆盖,再补 1 个业务例)

业务场景:查询 “数学成绩大于 90 分的学生姓名”
(子查询先找 “数学> 90 的学生 ID”,主查询用 ID 匹配姓名)

SELECT sname
FROM students
WHERE sid IN (SELECT sid  -- 子查询:找出数学分数>90的学生IDFROM scoresWHERE subject = '数学' AND score > 90
);
2. FROM 子句中的子查询(即表子查询,再补 1 个复杂例)

业务场景:查询 “每个班级中,语文成绩最高的学生姓名、班级名称和语文分数”
(子查询先算 “每个班级的语文最高分”,再关联表查具体学生)

SELECT s.sname, c.cname, sc.score
FROM students s
JOIN classes c ON s.cid = c.cid
JOIN scores sc ON s.sid = sc.sid
-- 关联“每个班级的语文最高分”临时表
JOIN (-- 子查询:按班级分组,算每个班级的语文最高分(班级ID、最高分)SELECT s.cid, MAX(sc.score) AS max_chineseFROM students sJOIN scores sc ON s.sid = sc.sidWHERE sc.subject = '语文'GROUP BY s.cid
) AS t ON s.cid = t.cid AND sc.score = t.max_chinese  -- 匹配班级+分数
WHERE sc.subject = '语文';  -- 确保只查语文成绩

结果示例:每个班级显示 1 名语文最高分学生,比如(张三,高三 1 班,98)、(李四,高三 2 班,95)。

3. SELECT 子句中的子查询(每行数据对应 1 个计算值)

业务场景:查询 “所有学生的姓名、数学分数,以及全校数学的平均分数”
(子查询算 “全校数学平均分”,主查询为每个学生行都显示这个平均分)

SELECT s.sname,sc.score AS math_score,-- 子查询在SELECT中,每行都显示同一个“全校数学平均分”(如82)(SELECT AVG(score) FROM scores WHERE subject = '数学') AS all_math_avg
FROM students s
JOIN scores sc ON s.sid = sc.sid
WHERE sc.subject = '数学';  -- 只查数学成绩

结果示例

snamemath_scoreall_math_avg
张三9582
李四7882
王五8582

关键总结

子查询的核心价值是 “拆分复杂逻辑”—— 把 “需要先算的条件 / 数据” 放在子查询中,主查询专注于 “最终筛选 / 展示”,所有例子的本质都是 “先算子查询,再用子查询结果帮主查询干活”,理解业务场景后就能灵活套用。

sql语句的执行顺序:

FROM 和 JOIN - 确定数据源

WHERE - 行级过滤

GROUP BY - 分组

HAVING - 组级过滤 ← 在这里!

SELECT - 选择列并可以定义别名

ORDER BY - 排序

LIMIT - 限制结果

http://www.dtcms.com/a/392612.html

相关文章:

  • MySQL的存储引擎(一条sql语句的执行流程是什么样的?)
  • JavaScript学习笔记(二):遍历方法汇总
  • Ubuntu22.04显卡掉驱动,重装命令
  • 模式组合应用-享元模式
  • 租房小程序房产小程序源码方案详解
  • p-value与e-value
  • 面经分享--京东一面
  • 大数据毕业设计选题推荐-基于大数据的帕金森病数据可视化分析系统-Spark-Hadoop-Bigdata
  • stack 和 queue
  • 执行yarn init报错:error Invalid package name.(question name)包名格式不对
  • Windows 下 PyTorch 入门深度学习环境安装与配置 CPU GPU 版 | 土堆教程
  • Transformer中为什么要使用多头注意力?
  • 《嵌入式硬件(十六):基于IMX6ULL的I2C的操作》
  • AI.工作助手.工作提效率
  • 【开题答辩全过程】以 Louis宠物商城为例,包含答辩的问题和答案
  • 微服务-网络模型与服务通信方式openfein
  • 如何快速定位局域网丢包设备?
  • 算法<java>——排序(冒泡、插入、选择、归并、快速、计数、堆、桶、基数)
  • 深入浅出CMMI:从混乱到卓越的研发管理体系化之路
  • Docker一键部署prometheus并实现飞书告警详解
  • 基于“开源AI大模型AI智能名片S2B2C商城小程序”的多平台资源位传播对直播营销流量转化的影响研究
  • 【设计模式】适配器模式 在java中的应用
  • 2013/07 JLPT听力原文 问题四
  • MyBatis 缓存体系剖析
  • MySQL 主从复制 + MyCat 读写分离 — 原理详解与实战
  • Vmake AI:美图推出的AI电商商品图编辑器,快速生成AI时装模特和商品图
  • Debian13 钉钉无法打开问题解决
  • 02.容器架构
  • Diffusion Model与视频超分(1):解读淘宝开源的视频增强模型Vivid-VR
  • 通过提示词工程(Prompt Engineering)方法重新生成从Ollama下载的模型