【SQL】子查询详解(附例题)

子查询

子查询的表示形式为:(SELECT 语句),它是INEXISTS等运算符的运算数,它也出现于FROM子句和VALUES子句。包含子查询的查询叫做嵌套查询。嵌套查询分为相关嵌套查询不想关嵌套查询

WHERE子句中的子查询

比较运算符

子查询的结果是元组的集合,即一个表,一般情况下,其关系模式有多列,关系实例有若干行。如果子查询的结果是一个单列且单行的表,则可作为比较运算符的运算对象

例1 查询与学号2000012的学生在同一个系的学生的详细信息

:本文所有例题涉及的关系实例如下:
在这里插入图片描述

学生信息都在Student表中;要查询全部信息,使用*选择所有列;查询条件是和学号为‘2000012’的学生同一个系。
可以先查询学号为‘2000012’的学生的系,再作为父查询的条件查询最终结果

SELECT *    --父查询
FROM Student
WHERE Sdept = (SELECT Sdept   --子查询FROM StudentWHERE Sno = '2000012');

查询结果
在这里插入图片描述
(实验环境:SQL Sever 2012)

上面的SQL语句的WHERE子句中出现了子查询,该语句的执行过程为:先执行子查询,得到一个值’计算机’,再用这个值替换子查询,得到一个新的SQL语句:

SELECT *    --父查询
FROM Student
WHERE Sdept = '计算机';

然后执行新的SQL语句,得到结果。

该例的子查询不依赖于父查询而单独执行,这样的嵌套查询叫做不相关嵌套查询

:查询选修了1156号课程并且成绩大于该课程平均成绩的学生的学号和成绩

SELECT Sno, Grade
FROM SC
WHERE Cno = '1156' AND Grade > (SELECT AVG(Grade)FROM SCWHERE Cno = '1156');

在这里插入图片描述
因为AVG是一个聚集函数,所以子查询返回一个单行单列的数据,可以按上述方法使用

如果子查询返回一个单列多行的表,则这个子查询不能直接出现在比较表达式,需要使用SOMEALL修饰符,SOME是值集合的某一元素,ALL代表集合的全体元素

:查询其他系比管理系某一学生年龄小的学生的姓名和年龄

查询管理系学生的年龄:

SELECT Sage
FROM Student
WHERE Sdept = '管理';

该查询结果为{18, 19, 19},不是一个单值。比某一学生年龄小要使用表达式Sage<SOME(18,19,19),如果Sage的值小于集合中某一元素的值,则比较结果为真,否则为假

SELECT Sname, Sage
FROM Student
WHERE Sdept <> '管理' AND Sage < SOME (SELECT SageFROM StudentWHERE Sdept = '管理');

在这里插入图片描述

上面的查询还可以使用聚集函数实现
比某一学生年龄就,就是要小于所有学生年龄的最大值

SELECT Sname, Sage
FROM Student
WHERE Sdept <>'管理' AND Sage < (SELECT MAX(Sage)FROM StudentWHERE Sdept = '管理');

:查询其他系比管理系所有学生年龄都小的学生的姓名和年龄

SELECT Sname, Sage
FROM Student
WHERE Sdept <> '管理' AND Sage < ALL(SELECT SageFROM StudentWHERE Sdept = '管理');

该查询同样可以使用聚集函数
比所有学生年龄小,就是要小于所有学生年龄的最小值

SELECT Sname, Sage
FROM Student
WHERE Sdept <>'管理' AND Sage < (SELECT MIN(Sage)FROM StudentWHERE Sdept = '管理');

在这里插入图片描述

不存在这样的学生,所以查询结果为空

SOME、ALL修饰符与聚集函数及谓词IN的对应关系如表所示

=<><<=>>=
SOMEIN<MAX<=MAX>MIN>=MIN
ALLNOT IN<MIN<=MIN>MAX>=MAX

:查询平均成绩不小于85分的学生的姓名和所在系

按照题意,设计查询过程:首先从Student表中任取一个学生,假设为x,然后从SC表中汇总出x的平均成绩,如果平均成绩不小于85,则输出x的姓名和所在系

求学生x的平均成绩的SQL语句为:

SELECT Sno, AVG(Grade)
FROM SC
WHERE Sno = x.Sno;

在SELECT语句中,除了表名、列名外,现在还出现了一个变量x,x叫做元组变量,表示某个表的一个元组。元组变量的名称只能是表名或表的别名,这样,通过元组变量的名称就知道它代表哪个表的元组

最终查询语句如下:

SELECT x.Sname, x.Sdept
FROM Student x
WHERE (SELECT AVG(Grade)FROM SCWHERE x.Sno = SC.Sno) > 85;

在这里插入图片描述
这样的嵌套查询叫做相关嵌套查询,因为子查询有一个变量x,当未确定x的值时,无法得到查询结果,而x代表父查询的元组,与父查询相关。不相关嵌套查询的子查询先于父查询执行,并且只执行一次,而相关嵌套查询对父查询的每个元组都要执行一次子查询

上述语句的执行过程如下:

  1. 执行父查询,顺序扫描Student表

  2. 取Student表的一个元组赋予元组变量x

  3. 执行父查询的WHERE子句

    • 将第2步获取的x传送到子查询
    • 执行子查询,得到平均成绩
    • 判断平均成绩是否大于等于85
  4. 如果WHERE子句的条件为真,则输出x.Sname和x.Sdept

  5. 重复步骤2~4,继续处理下一个元组,直到处理完Student表的所有元组

为了易于理解,可以使用表名作为元组变量名

谓词IN

谓词IN是二元运算符,一般书写形式为A IN S,A是一个列名,S是一个集合。如果A是集合S的元素,则结果为真,否则结果为假

:查询选修了1024号课程的学生的姓名和所在系

本例涉及Student表和SC表,分两步构造。首先在SC表中查询选修了1024号课程的学生集合,记为S

SELECT Sno
FROM SC
WHERE Cno = '1024';

然后对Student表的每个元组t,如果t.Sno∈S成立,则t是查询结果之一。使用IN代替∈,使用元组变量表示t,就得到了下面的SQL语句

SELECT t.Sname, t.Sdept
FROM Student t
WHERE t.Sno IN(SELECT SnoFROM SCWHERE Cno = '1024');

在这里插入图片描述
也可以直接用表名做为元组变量

SELECT Student.Sname, Student.Sdept
FROM Student
WHERE Student .Sno IN(SELECT SnoFROM SCWHERE Cno = '1024');

上述语句执行过程为:先执行子查询,得到一个选了1024号课程的学生的集合,再执行外查询,对Student表中的每个元组,测试元组在Sno列上的分量值是否在子查询的结果中,如满足则输出这个元组

:查询选修了“管理学”的学生学号和姓名

选修了管理学的学生:

SELECT Sno
FROM SC, Course
WHERE SC.Cno = Course.Cno AND Course.Cname = '管理学';

判断Student表中的每个元组在Sno上的分量是否在学生集合中,得:

SELECT Sno, Sname
FROM Student
WHERE Student.Sno IN(SELECT SnoFROM SC, CourseWHERE SC.Cno = Course.Cno AND Course.Cname = '管理学');

SELECT Sno, Sname
FROM Student
WHERE Sno IN(SELECT SnoFROM SCWHERE Cno IN(SELECT CnoFROM CourseWHERE Cname = '管理学'));

在这里插入图片描述

谓词EXISTS

谓词EXISTS是一元运算符,运算数是一个集合,如果该集合不是空集,则运算结果为真,否则运算结果为假。

:查询所有选修了1024号课程的学生的姓名

SELECT Sname
FROM Student
WHERE Sno IN (SELECT SnoFROM SCWHERE Cno='1024');

这是一个不相关嵌套查询,也可以使用EXISTS谓词实现

对Student表的任何一个元组x,如果选修了1024号课程,则SC表中存在x的选课记录,该记录在Sno列上的分量等于x.Sno,在Cno上的分量等于’1024’。因此,集合SELECT * FROM SC WHERE Sno = x.Sno AND Cno = '1024'一定不是空集,则表达式EXISTS(SELECT * FROM SC WHERE Sno = x.Sno AND Cno = '1024)为真;如果x没有选修1024号课程,则表达式结果为假

SELECT x.Sname
FROM Student x
WHERE EXISTS(SELECT *FROM SCWHERE Sno = x.Sno AND Cno = '1024');

在这里插入图片描述
:查询至少选修了学号为2000014的学生所选修的全部课程的学生的姓名及所在系

用R表示学号为2000014的学生所选修的全部课程的集合,S表示学生x选修的全部课程的集合,如果R⊆S成立,则x是要查找的学生

SELECT x.Sname x.Sdept
FROM Student x
WHERE x.Sno!='2000014' ANDNOT EXISTS (SELECT t.CnoFROM SC tWHERE Sno='2000014' AND NOT EXISTS(SELECT CnoFROM SCWHERE Sno = x.Sno AND Cno=t.Cno));

:查询与学号为2000014的学生所选修的课程相同的学生的姓名

用R表示学号为2000014的学生选修的所有课程的集合,用S表示学生x选修的课程,如果R=S,则x是要查询的学生

SELECT Student x
FROM Student x
WHERE x.Sno != '2000014' AND NOT EXISTS (SELECT Cno			--R∈SFROM SC yWHERE Sno = '2000014' AND NOT EXISTS(SELECT CnoFROM SCWHERE Sno = x.Sno AND Cno = y.Cno))ANDNOT EXISTS (SELECT CnoFROM SC zWHERE Sno = x.Sno AND NOT EXISTS(SELECT CnoFROM SCWHERE Sno = '2000014' AND Cno = z.Cno));

FROM 子句中的子查询

FROM子句可以指定查询要使用的表。子查询的结果是一个表,但只是一个中间结果,并没有存放在数据库。为了在FROM子句使用子查询,要给子查询生成的临时表命名,有时还要命名临时表的列

:查询每门课的名称和平均成绩

首先可以很容易的写出查询每门课的课程号和平均成绩的SQL语句

SELECT Cno, AVG(Grade)
FROM SC
GROUP BY Cno;

在这里插入图片描述
为了得到课程的名字,将临时表和Course表连接即可

SELECT Cname, Grade
FROM Course, (SELECT Cno, AVG(Grade)FROM SCGROUP BY Cno) AS tmp(Cno, Grade)  --命名临时表
WHERE Course.Cno = tmp.Cno;

也可以使用连接操作和分组操作实现

SELECT Cname, AVG(Grade)
FROM Course, SC
WHERE Course.Cno = SC.Cno
GROUP BY Cname;

外连接

使用条件连接运算时,只有满足连接条件的元组才能作为查询条件。假设A表和B表做条件连接,有时A表中会有某个元组t,由于在B表中没有任何一个元组满足与t的连接条件,因此t不会出现在连接结果中。

为了解决参与连接的表的某些元组没有出现在连接结果中的问题,需要使用左外连接右外连接全外连接运算,作为区分,前面介绍的连接叫做内连接

左外连接

A表和B表做左外连接,其过程是先按照连接条件做连接运算,得到一个结果。如果A的某个元组t不在结果中,则将t和B的一个“万能元组”做连接,这个万能元组在所有列上取空值,即(NULL, NULL, …, NULL),形成一个新元组,加入最终结果。这个“万能元组”并不真实存在

表达为

A LEFT OUTER JOIN B ON Condition

Course表和SC表做左外连接运算,物理课出现在查询结果中

SELECT *
FROM Course LEFT OUTER JOIN SC ON Course.Cno = SC.Cno

在这里插入图片描述

右外连接

A表和B表做右外连接,其过程是先按照连接条件做连接运算,得到一个结果。如果B的某个元组t不在结果中,则将t和A的一个“万能元组”做连接,形成一个新元组,加入最终结果。

表达为

A RIGHTOUTER JOIN B ON Condition

全外连接

全外连接是左外连接右外连接

:查询每门课的选修人数

根据题意,查询结果需要包括每门课程,所以使用左外连接,然后对查询结果分组、统计

有两种写法:

SELECT Cname, COUNT(*)
FROM Course LEFT OUTER JOIN SC ON Course.Cno = SC.Cno
GROUP BY Cname;

在这里插入图片描述

SELECT Cname, COUNT(Sno)
FROM Course LEFT OUTER JOIN SC ON Course.Cno = SC.Cno
GROUP BY Cname;

在这里插入图片描述

COUNT(*)函数用于统计分组中的元组数,不会省略值为NULL的元组,所以尽管无人选修物理课,任然会计数1,这是错误的;而COUNT(Sno)在计数时舍弃了NULL值,所以统计结果为0,是符合要求的

未完待续…

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/901022.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Stable Diffusion 扩展知识实操整合

本文的例子都是基于秋叶整合包打开的webui实现的 一、ADetailer——改善人脸扭曲、恶心 After detailer插件可以自动检测生成图片的人脸&#xff0c;针对人脸自动上蒙版&#xff0c;自动进行重绘&#xff0c;整个流程一气呵成&#xff0c;因此可以避免许多重复的操作。除此之…

freertos内存管理简要概述

概述 内存管理的重要性 在嵌入式系统中&#xff0c;内存资源通常是有限的。合理的内存管理可以确保系统高效、稳定地运行&#xff0c;避免因内存泄漏、碎片化等问题导致系统崩溃或性能下降。FreeRTOS 的内存管理机制有助于开发者灵活地分配和释放内存&#xff0c;提高内存利用…

按规则批量修改文件扩展名、删除扩展名或添加扩展名

文件的扩展名是多种多样的&#xff0c;有些不同文件的扩展名之间相互是可以直接转换的。我们工作当中最常见的就是 doc 与 docx、xls 与 xlsx、jpg 与 jpeg、html 与 htm 等等&#xff0c;这些格式在大部分场景下都是可以相互转换 能直接兼容的。我们今天要介绍的就是如何按照一…

热门面试题第15天|最大二叉树 合并二叉树 验证二叉搜索树 二叉搜索树中的搜索

654.最大二叉树 力扣题目地址(opens new window) 给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下&#xff1a; 二叉树的根是数组中的最大元素。左子树是通过数组中最大值左边部分构造出的最大二叉树。右子树是通过数组中最大值右边部分构造出的最大…

MySQL学习笔记7【InnoDB】

Innodb 1. 架构 1.1 内存部分 buffer pool 缓冲池是主存中的第一个区域&#xff0c;里面可以缓存磁盘上经常操作的真实数据&#xff0c;在执行增删查改操作时&#xff0c;先操作缓冲池中的数据&#xff0c;然后以一定频率刷新到磁盘&#xff0c;这样操作明显提升了速度。 …

RNN、LSTM、GRU汇总

RNN、LSTM、GRU汇总 0、论文汇总1.RNN论文2、LSTM论文3、GRU4、其他汇总 1、发展史2、配置和架构1.配置2.架构 3、基本结构1.神经元2.RNN1. **RNN和前馈网络区别&#xff1a;**2. 计算公式&#xff1a;3. **梯度消失:**4. **RNN类型**:&#xff08;查看发展史&#xff09;5. **…

django数据迁移操作受阻

错误信息&#xff1a; django.db.utils.OperationalError: (1227, Access denied; you need (at least one of) the SYSTEM_VARIABLES_ADMIN or SESSION_VARIABLES_ADMIN privilege(s) for this operation)根据错误信息分析&#xff0c;该问题是由于MySQL用户 缺乏SYSTEM_VARI…

WinForm真入门(13)——ListBox控件详解

WinForm ListBox 详解与案例 一、核心概念 ‌ListBox‌ 是 Windows 窗体中用于展示可滚动列表项的控件&#xff0c;支持单选或多选操作&#xff0c;适用于需要用户从固定数据集中选择一项或多项的场景‌。 二、核心属性 属性说明‌Items‌管理列表项的集合&#xff0c;支持动…

局域网内文件共享的实用软件推荐

软件介绍 在日常办公、学习或家庭网络环境里&#xff0c;局域网内文件共享是个常见需求。有一款免费的局域网共享软件非常适合这种场景。 这款局域网共享软件使用起来非常简单&#xff0c;不需要安装&#xff0c;直接点击就能使用。 它的操作流程简单易懂&#xff0c;用户只要…

ViewModel vs AndroidViewModel:核心区别与使用场景详解

在 Android 的 MVVM 架构中&#xff0c;ViewModel 和 AndroidViewModel 都是用于管理 UI 相关数据的组件&#xff0c;但二者有一些关键区别&#xff1a; 1. ViewModel 基本用途&#xff1a;用于存储和管理与 UI 相关的数据&#xff0c;生命周期与 Activity/Fragment 解耦&…

C语言--求n以内的素数(质数)

求n以内的素数&#xff0c;可以用试除法或者埃拉托斯特尼筛法&#xff08;埃氏筛法&#xff09; 文章目录 试除法埃拉托斯特尼筛法&#xff08;埃氏筛法&#xff09;两种方法测试运行效率 输入&#xff1a;数字n 输出&#xff1a;n以内所有的素数 不管是哪个方法&#xff0c;都…

Skynet.socket 函数族使用详解

目录 Skynet.socket 函数族使用详解核心功能分类一、TCP 连接管理1. 监听端口2. 建立连接3. 关闭连接 二、数据读写操作1. 阻塞式读取2. 写入数据2.1 socket.write(fd, data) 的返回值2.2 示例代码2.3 关键注意事项2.4 与其他函数的区别2.5 底层原理2.6 总结 三、UDP 处理1. 创…

Unity Addressables资源生命周期自动化监控技术详解

一、Addressables资源生命周期管理痛点 1. 常见资源泄漏场景 泄漏类型典型表现检测难度隐式引用泄漏脚本持有AssetReference未释放高异步操作未处理AsyncOperationHandle未释放中循环依赖泄漏资源相互引用无法释放极高事件订阅泄漏未取消事件监听导致对象保留高 2. 传统管理…

aws(学习笔记第三十八课) codepipeline-build-deploy-github-manual

文章目录 aws(学习笔记第三十八课) codepipeline-build-deploy-github-manual学习内容:1. 整体架构1.1 代码链接1.2 全体处理架构2. 代码分析2.1 创建`ImageRepo`,并设定给`FargateTaskDef`2.2 创建`CodeBuild project`2.3 对`CodeBuild project`赋予权限(`ECR`的`image rep…

在windows服务器使用Nginx反向代理云端的python实现的web应用

近日得闲&#xff0c;计划将之前写过的一些小桌面程序搬到云服务器上方便随时随地使用&#xff0c;同时也学习一些基本的网站开发和搭建知识&#xff0c;于是在AI的帮助下&#xff0c;基于niceguifastapi非常快捷地搞出来了一个前后端一体的网站程序&#xff0c;放在云服务器上…

全球贸易战火重燃:50%关税如何绞杀跨境电商低价模式?

一、政策高压&#xff1a;美国对华贸易战升级路线图 2024年5月&#xff0c;美国国会《数字贸易壁垒法案》草案曝光&#xff0c;标志着中美贸易博弈进入新阶段&#xff1a; • 关税武器精准打击&#xff1a;成衣、消费电子、小家电税率拟从10-25%跃升至50% • 监管范围扩大&…

0411 | 软考高项笔记:项目立项

在软考的项目管理知识体系中&#xff0c;技术可行性和经济可行性是项目立项阶段非常重要的两个分析维度。以下是对这两个考点的详细解释和记忆方法&#xff1a; 技术可行性分析 定义&#xff1a; 技术可行性分析是评估项目在现有技术条件和资源下是否能够成功实施。它主要回答…

二分查找3:69. x 的平方根

链接&#xff1a;69. x 的平方根 - 力扣&#xff08;LeetCode&#xff09; 题解&#xff1a; 本题本质是二分查找右端点 x的算数平方根一定在1 ~ x 区间内&#xff0c;在1 ~ x区间内查找一个数num&#xff0c;num^2x&#xff0c;但实际上num不一定是整数&#xff0c;所以是n…

oracle大师认证证书有用吗

专业能力的高度认可&#xff1a;OCM 是 Oracle认证的最高级别&#xff0c;是对数据库从业人员技术、知识和操作技能的最高级认可&#xff0c;也是 IT 界顶级认证之一。它表明持证者具备处理关键业务数据库系统和应用的能力&#xff0c;能够解决最困难的技术难题和最复杂的系统故…

InnoDB 如何解决幻读:深入解析与 Java 实践

在数据库事务管理中&#xff0c;幻读&#xff08;Phantom Read&#xff09;是并发操作中常见的问题&#xff0c;可能导致数据一致性异常。MySQL 的 InnoDB 存储引擎通过其事务隔离机制和多版本并发控制&#xff08;MVCC&#xff09;&#xff0c;有效解决了幻读问题。作为 Java …