《数据库系统概论》之相关子查询与不相关子查询

article/2025/10/13 12:18:55

文章目录

  • 前言
  • 数据表
  • 一、子查询(subquery)
  • 二、不相关子查询(unrelated subqueries)
    • 1.概念
    • 2.查询逻辑
  • 三、相关子查询(related subqueries)
    • 1.概念
    • 2.查询逻辑
    • 3.带有EXISTS谓词的子查询
  • 总结


前言

开篇感言

第一次发文章,源于今天下午上课时,相关子查询讲得台下学生一脸懵逼。为了不误人子弟与自己卑微的尊严,故有此文 。如果还没懂,随时找我,欢迎留言。


一些说明
本文所用概念与示例大多引用自王珊老师的《数据库系统概论》第5版,部分原创。


以下是本篇文章正文内容

数据表

1、Student(学生表)

SnoSnameSsexSageSdept
201215121李勇20CS
201215122刘晨19CS
201215123王敏18MA
201215125张立19IS

2、Course(课程表)

CnoCnameCpnoCcredit
1数据库54
2数学2
3信息系统14
4操作系统63
5数据结构74
6数据处理2
7PASCAL语言64

3、SC(选课表/成绩表)

SnoCnoGrade
201215121192
201215121285
201215121388
201215122290
201215122388

一、子查询(subquery)

查询块:在SQL语言中,一个"SELECT-FROM-WHERE"语句称为一个查询块。
嵌套查询:将一个查询块嵌套在另一个查询块的WHERE子句或HAVING短语的条件中的查询称为嵌套查询(nested query)。

例1:查询选择了2号课程的学生姓名(数据表见上文)

SELECT Sname                           /*外层查询或父查询*/
FROM Student
WHERE Sno IN(SELECT Sno                     /*内层查询或子查询*/FROM SCWHERE Cno = '2')

例1中,下层查询块被嵌套于上层查询的WHERE条件中,其中下层查询称为内层查询或子查询,上层查询称为外层查询或父查询

二、不相关子查询(unrelated subqueries)

1.概念

不相关子查询:子查询的查询条件不依赖于父查询,称为不相关子查询。
以上文例1为示例,子查询的查询条件为WHERE Cno = ‘2’,与父查询毫无关联,相互独立,因此为不相关子查询,也称为独立子查询(independent subqueries)。

2.查询逻辑

不相关子查询的查询逻辑为:
step1:先执行子查询,得到选择了2号课程的学生学号集合
step2:再执行父查询,把上一步的学号集合作为条件,从Student表中找出这些学生的姓名
不相关子查询非本文重点,不再赘述

三、相关子查询(related subqueries)

1.概念

相关子查询:顾名思义,子查询的查询条件依赖于父查询,这类子查询称为相关子查询。

2.查询逻辑

相关子查询的查询逻辑为(四步曲):

  • step1:先取元组,从父查询中取出一个元组,并将元组的相应属性值给子查询
  • step2:执行子查询,按上一步得到的条件执行子查询,并将执行后的结果作为父查询的条件
  • step3:执行父查询
  • step4:取下一个元组循环上述三步

如果感觉有点绕,没关系,看例子

例2:找出每个学生超过他自己选修课程平均成绩的课程号(数据表见上文)

SELECT Sno, Cno
FROM SC x             /*x为表SC的别名,又称为元组变量,表示SC的一个元组*/
WHERE Grade >(SELECT AVG(Grade)FROM SC yWHERE y.Sno = x.Sno)
  • step1:先取元组,从父查询SC中取第一个元组x如下,由于子查询中需要x.sno,因此此时y.Sno = ‘201215121’。
SnoCnoGrade
201215121192
  • step2:执行子查询,按y.Sno = '201215121’执行子查询,结果为’201215121’的平均成绩AVG(Grade),即88分(近似值),并将其作为父查询的条件。
  • step3:执行父查询,找到’201215121’学生成绩>88的课程,即1号课程,92分。
  • step4:从父查询SC中取下一个元组循环上述三步,直到父查询SC中无元组可取,得到查询结果如下:
SnoCno
12012151211
22012151222

注意:相关子查询的求解不会一次将子查询求解出来,而是要去遍历父查询的元组来求解子查询。你可以把这个过程理解为一个FOR循环,从父查询表中的第一个元组遍历到最后一个元组

3.带有EXISTS谓词的子查询

EXISTS谓词代码存在量词 ∃
带有EXISTS谓词的子查询不返回任何数据,只产生逻辑真值“true”或逻辑假值“false”。

  1. 若内层查询结果非空,则外层的WHERE子句返回真值
  2. 若内层查询结果为空,则外层的WHERE子句返回假值

由EXISTS引出的子查询,其目标列表达式通常都用 * ,因为带EXISTS的子查询只返回真值或假值,给出列名无实际意义。

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

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

我们注意观察代码,子查询WHERE条件中“Sno=Student.Sno”,也就是说子查询的条件依赖父查询,因此这是相关子查询
回顾并试一试相关子查询“四步曲”:

  • step1:先取元组,从父查询Student中取第一个元组如下,由于子查询中需要Student.Sno,因此只用把该元组中的Sno(201215121)给子查询去用就行了。
SnoSnameSsexSageSdept
201215121李勇20CS
  • step2:执行子查询,按条件(Sno=201215121 AND Cno= ‘1’)执行子查询,发现SC中可以找到201215121学习了课程1,结果非空,父查询的WHERE子句返回真值
  • step3:执行父查询,可以理解为把上述元组的Sname放入结果表中,即“李勇”。
  • step4:从父查询Student中取下一个元组循环上述三步,直到父查询Student中无元组可取。

注意:重难点来了,这也是我为什么写这篇文章的原因
NOT EXISTS谓词(重点、难点):

  1. 若内层查询结果非空,则外层的WHERE子句返回假值
  2. 若内层查询结果为空,则外层的WHERE子句返回真值

粗看起来,NOT EXISTS谓词就是和EXISTS相反,但它的用处远远大于EXISTS
先看书上例题:

例4:查询没有选修了1号课程的学生姓名

SELECT Sname
FROM Student
WHERE NOT EXISTS(SELECT *FROM SCWHERE Sno=Student.Sno AND Cno= '1')

例4和例3唯一的区别就是把EXISTS换成了NOT EXISTS:

  1. 如果一个学生学习了1号课程,内层查询结果非空,外层的WHERE子句返回假值,这个学生不被放入结果表;
  2. 如果一个学生没学习1号课程,内层查询结果为空,外层的WHERE子句返回真值,这个学生会被放入结果表。

例5:查询选修了全部课程的学生姓名

SELECT Sname
FROM Student
WHERE NOT EXISTS(SELECT *FROM CourseWHERE NOT EXISTS(SELECT *FROM SCWHERE Sno= Student.SnoAND Cno= Course.Cno))

书上没有什么解释直接给了以上这段代码,让人莫名,这也是为什么大家难以理解的原因之一。我这里先不和大家绕存在与不存在,先看另一个问题。

例6:查询学生“201215121”没有选的课程名

SELECT Cname 
FROM course  
WHERE not exists(SELECT * FROM SC WHERE cno = course.cno and sno = “201215121”)

我们要看一个学生(学生已知为“201215121”)没选什么课,可以拿着Course表里每一门课去SC表里面找,看这位学生到底有没有学。
因此我们可以想到采用相关子查询“遍历”的思想,在父查询中查Course表,遍历Course表中的每一个元组放进子查询SC中。而父、子查询就涉及了这两个表的连接,因此子查询中还需要加入条件cno = course.cno。注:左边的cno其实就是sc.cno
执行过程如下:

  1. 取Course表中第一个元组(即课程1),在SC表中找cno = ‘1’ and sno = '201215121’的元组是不是存在,显然存在,因此子查询非空,not exists非空为假,所以1号课程不加入结果表;
  2. 取Course表中第二个元组(即课程2),在SC表中找cno = ‘2’ and sno = '201215121’的元组是不是存在,显然存在,因此子查询非空,not exists非空为假,所以2号课程不加入结果表;
  3. 取Course表中第三个元组(即课程3),在SC表中找cno = ‘3’ and sno = '201215121’的元组是不是存在,显然存在,因此子查询非空,not exists非空为假,所以2号课程不加入结果表;
  4. 取Course表中第四个元组(即课程4),在SC表中找cno = ‘4’ and sno = '201215121’的元组是不是存在,发现不存在,因此子查询为空,not exists非空为真,所以4号课程(操作系统)加入结果表
  5. 同理5(数据结构)、6(数据处理)、7(PASCAL)号课程也加入结果表
    在这里插入图片描述

再回到例5:查询选修了全部课程的学生姓名

选修了全部课程,等价于“没有课程没有选修”
而我们在例6中已经知道怎么找某一学生没有选修的课程,所以我们只需要在这个结果上再套用一层not exists,就可以得出没有课程没有选修,并将其拓展至所有学生。

或者这样理解:学生未知,课程未知,我们想知道没有课程没有选修的学生,需要用两层FOR循环(两层not exists),第一层遍历所有学生(用Student表),第二层遍历所有课程(用Course表),再在SC表中,看遍历的值是否存在。

SELECT Sname                /*找到一个学生---方式为遍历学生表*/
FROM Student
WHERE NOT EXISTS          /*不存在一门课程--方式为遍历课程表*/(SELECT *                   FROM CourseWHERE NOT EXISTS    /*没有选修--方式为遍历选课表来比对(Sno, Cno)*/(SELECT *               FROM SCWHERE Sno= Student.SnoAND Cno= Course.Cno))

以执行过程如下:

  1. 取Student表中第一个元组(201215121),并遍历Course表中每一个元组(1至7),在SC表中找这7种组合可能是不是都存在,显然没有,说明学生“201215121”有课没选修,排除这个学生。
  2. 取Student表中第二个元组(201215122),并遍历Course表中每一个元组(1至7),在SC表中找这7种组合可能是不是都存在,显然没有,说明学生“201215122”有课没选修,排除这个学生。
  3. 同理。。。。。

你也可以通过两层FOR循环来理解:

for(在Student表中遍历Sno){for(在Course表中遍历Cno){在SC表中看 Sno= Student.Sno AND Cno= Course.Cno 是否满足如果都满足,说明这个学生选修了所有课如果有一门课不满足,说明这个学生没有选修所有课}
}

尽力了,不懂的话多看一遍?最好是写代码测试一下
提示:这个题还有另一种方法,就是找到选修课程数 = 课程总数的学生,代码如下:

SELECT Sname
FROM Student
WHERE Sno IN (SELECT SnoFROM SCGROUP BY Sno     /*以Sno */HAVING COUNT(*)=(SELECT COUNT(*)   /*所有课程的门数*/FROM Course))

书上最后一个例题,就留给大家自己去理解了,累了。。。

例7:查询至少选修了学生201215122选修的全部课程的学生号码

即:不存在这样的课程,学生201215122选修了,而某学生没有选

SELECT DISTINCT Sno
FROM SC SCX
WHERE NOT EXISTS(SELECT *FROM SC SCYWHERE SCY.Sno = '201215122' AND NOT EXISTS(SELECT *FROM SC SCZWHERE SCZ.Sno=SCX.Sno AND SCZ.Cno=SCY.Cno))

总结

没什么好总结的,多做几个题,直接就明白了


http://chatgpt.dhexx.cn/article/pLOLR7V7.shtml

相关文章

变量之间的相关性研究

目录 1 什么是相关性?协方差及协方差矩阵相关系数(1)简单相关分析(2)偏相关分析(3)复相关分析(4)典型相关分析 2 对已有数据的预分析2.1 绘制变量相关的热力图2.2 对热力…

独立=>不相关

独立 ⇒ \Rightarrow ⇒不相关 文章目录 独立 ⇒ \Rightarrow ⇒不相关判定定理独立性 F ( x , y ) F X ( x ) F Y ( y ) F(x,y)F_X(x)F_Y(y) F(x,y)FX​(x)FY​(y)证明不独立只需要用P(AB)≠P(A)P(B)举反例离散型连续型 不相关 ρ x y 0 \rho_{xy}0 ρxy​0(协方差为0) 性质…

MySQL 不相关子查询怎么执行?

1. 概述 从现存的子查询执行策略来看,半连接 (Semijoin) 加入之前,不相关子查询有两种执行策略: 策略 1,子查询物化,也就是把子查询的执行结果存入临时表,这个临时表叫作物化表。 explain select_type …

为什么相关不等于因果

为什么相关不等于因果 十九世纪末,荷兰出现了一个奇怪的现象:人口出生率与当地白鹳的数量同步增长。鹳鸟送子的传说由此而来。虽然这个故事逐渐消失在民间传说中,但现实生活中类似的相关性无处不在。二十世纪和二十一世纪的新研究一再证实&a…

独立正交不相关定义关系

一、“独立”、“不相关”和“正交”的定义 假设X为一个随机过程,则在t1和t2时刻的随机变量的相关定义如下(两个随机过程一样): (1)定义Rx(t1,t2)E{X(t1&…

不相关、独立、正交的区别与联系

1.相关定义说明: 随机过程:X(t)和Y(t)互相关函数:Rxy(t1,t2)E{X(t1)Y(t2)}互协方差函数:Cxy(t1,t2)E{[X&…

不独立 ≠ 不相关 (Independent ≠ Uncorrelated)

在数学期望的性质里有一个性质:随机变量X和Y相互独立,有:E(XY) E(X)E(Y). 事实上这里成立的充要条件是X和Y不相关即可。 那么问,相互独立与不相关的关系是什么呢? 独立性是指两个变量的发生概率一点关系没有;而相关…

View For EasyUI 后台模板html

ViewUI For EasyUI View For EasyUi是基于EasyUI-1.5x开发的前端UI框架主题皮肤,包含所有EasyUI的全部组件美化, 还有各种插件,各种优化 ,完全使用矢量图标,每一个小图标都是矢量图标,支持无限放大和颜色设…

easyui了解

目录 一、框架概述 1、什么是Easyui? 2、EasyUI的常用组件 3、EasyUI的特点 缺点 使用: 4、EasyUI的目录说明 4.1 下载路径 4.2 必须的基础支持库 4.3 目录说明 二、WEB项目搭建EasyUI环境 1.EasyUI入门示例 1.1 标准开发步骤 1.2 代码模板 …

JQuery EasyUI-1.5.x-Of-Insdep-Theme后台模板

简介: JQuery easyui 1.5.x of Insdep Theme 1.0.0 RC2,是基于EasyUI 1.5.x 的一款免费的美化主题包,拥有百度编辑器、cropper、Highcharts、justgage、plupload等各类适应本主题的第三方插件美化补丁。并且各类常用Jquery插件正在美化中。 …

easyui自学模板代码

index.jsp源码 <% page language"java" contentType"text/html; charsetUTF-8"pageEncoding"UTF-8"%><% taglib uri"http://java.sun.com/jsp/jstl/core" prefix"c"%> <c:set var"ctx" value"…

easyui酷黑风格主题模板组件html

模板简介&#xff1a;基于easyui目前最新版本1.10.X设计制作&#xff0c;后期会随easyui版本进行响应更新。模板仅修改easyui默认的css样式文件&#xff0c;可以很方便的与默认主题进行替换或切换。对于已有项目&#xff0c;可以快速的替换主题&#xff0c;不影响系统功能。对e…

使用easyui快速搭建管理员主界面

使用easyui快速搭建管理员主界面 easyui主页&#xff1a;index.jspsidebarTree.json&#xff1a;左侧菜单内容 easyui easyui又叫Jquery EasyUI&#xff0c;是基于Jquery的界面框架插件&#xff0c;提供了丰富的界面功能&#xff0c;方便快速开发Web界面程序 目前easyui的官方网…

easyui poi 一个模板导出多个模板数据,在一个sheet中导出

easyui poi 一个模板导出多个模板数据&#xff0c;在一个sheet中导出 1.示例代码2.模拟数据3.导出模板4.导出效果 1.示例代码 /*** 导出excel表格** return excel 文件流*/ResponseExcelApiOperation(value "导出excel表格", notes "导出详情excel表格"…

easyui首页模板

Easyui首页html代码 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head><meta name"renderer" content"webkit"></meta><tit…

easyui_datagrid模板代码

<!DOCTYPE html> <html><head><meta charset"utf-8" /><title>jquery_easyui模板代码</title><link rel"stylesheet" type"text/css" href"js/jquery-easyui-1.7.0/themes/default/easyui.css"…

easyui(基础布局)

一.easyUI的简介 easyui是一款基于jQuery的前端框架&#xff0c;可以使用其中的组件进行布局以及用来做后台的管理界面。 EasyUI是一个前端开发的框架&#xff0c;其将常用的页面开发使用的组件进行了封装&#xff0c;前端开发人员只需将EasyUI的资源导入项目后使用即可&am…

jquery easyui后台模板

上一篇教程《asp.net mvcjquery easyui开发实战教程之网站后台管理系统开发3-登录模块开发》完成了本项目的登录模块&#xff0c;登录后就需要进入后台管理首页了&#xff0c;需要准备一个后台模板&#xff0c;本文主要讲解如何创建这个后台模板&#xff0c;本文创建的后台模板…

easyui-super-theme后台模板

简介&#xff1a; 基于easyui最新版1.5.1的一套皮肤&#xff0c;flat ui的配色&#xff0c;字体图标用的是fontawesome 模板使用方式&#xff1a; 皮肤是基于gray主题修改的 把dist下的super主题文件夹考到easyui/themes文件夹下面 依次引入&#xff08;跟其他easyui主题用…

抓取京东评论数据

京东&#xff0c;淘宝等的评论数据貌似无法直接在源代码中查看&#xff0c;那么如何找到对应的评论数据的源代码文件呢&#xff1f; 这里要用到chrome浏览器的审查元素功能&#xff0c;以京东为例&#xff0c;点开一个评论页面&#xff0c; 然后在chrome中选择network的scr…