SQL 中的 EXISTS 到底做了什么?

本文中提到的所有数据表基于王珊《数据库系统概论(第4版)》。

个人认为 SQL 中的 EXISTS 关键字对于初学者来说是比较难理解的一个,尤其是多个 EXISTS 子句的嵌套。我就写篇小文章,来简单地来解释下 EXISTS 到底做了些什么。

我们先从 SQL 中最基础的 WHERE 子句开始。

比如下面这条 SQL 语句:

很显然,在执行这条 SQL 语句的时候,DBMS 会扫描 Student 表中的每一条记录,然后把符合 Sdept = ‘IS‘ 这个条件的所有记录筛选出来,并放到结果集里面去。也就是说 WHERE 关键字的作用就是判断后面的逻辑表达式的值是否为 True。如果为 True,则将当前这条记录(经过 SELECT 关键字处理后)放到结果集里面去,如果逻辑表达式的值为 False 则不放。

接下来看使用了 EXISTS 关键字的一条 SQL 语句:

这条 SQL 语句的作用,就是查找所有选修了 1 号课程的课程的学生,并显示他们的姓名。

我们先不管 EXISTS 关键字在其中起了什么作用,而是先来看子查询中的 WHERE 关键字后的表达式 Sno = Student.Sno AND Cno = ‘1‘。

其中的 Sno = Student.Sno 是怎么一回事?

这就涉及到 SQL 中的不相关子查询与相关子查询了。

我们常见的带子查询的 SQL 语句是这样的:

首先通过子查询得到课名为 “数据结构” 的课程的课号,然后遍历 SC (选课)表中的每一条选课记录,若当前这条记录的课号为 “数据结构” 这门课的课号,则将这条记录的 Sno 列的值放到结果集里面去。最终我们可以得到所有选修了 ”数据结构“ 这门课的学生的学号。

这种类型的查询是先执行子查询,得到一个集合(或值),然后将这个集合(或值)作为一个常量带入到父查询的 WHERE 子句中去。如果单纯地执行子查询,也是可以成功的。

这种类型的查询,叫做 ”不相关子查询“。

大多数情况下,不相关子查询已经够用了,但是如果有这样的一个查询要求:

子查询可以这么写:

那么问题来了, ? 处应该写什么值?

关键问题就是,? 处这个常量,并不是一个确定的值,而应该是不断地将 Student 表中的每一条记录中的 Sno 列的值代入此处,然后求出该 Sno 对应的平均成绩。我们需要的是输入一系列的值,然后得到一系列对应的输出。

这个时候,我们就要用到另一种嵌套查询,叫做 “相关子查询”。“相关子查询” 的意思就是,子查询中需要用到父查询中的值。

对于这个查询要求,我们可以使用以下 SQL 语句:

其工作原理就是,扫描父查询中数据来源(如 SC 表)中的每一条记录,然后将当前这条记录中的,在子查询中会用到的值代入到子查询中去,然后执行子查询并得到结果(可以看成是返回值),然后再将这个结果代入到父查询的条件中,判断父查询的条件表达式的值是否为 True,若为 True,则将当前 SC 表中的这条记录(经过 SELECT 处理)后放到结果集中去。若为 False 则不放。

在这个例子中,父查询先从 SC 表中取出第一条记录,然后将当前这条记录的 Sno 列的值(如 95001)代入到子查询中,求出学号为 95001 的学生选修的所有课程的平均分(如 80 分)。然后将这个 80 作为 Grade >= 后面的值代入,若 SC 表中的第一条记录的 Grade 列的值为 90,那么 Grade >= 80 这个条件表达式的值为 True,则将当前这条记录中的 Cno 列的值(如1)放入结果集中去。以此类推,遍历 SC 表中的所有记录,即可得到每个超过学生超过他/她所有课程平均分的课程的课号了。

判断是否是 “相关子查询” 也很简单,只要子查询不能脱离父查询单独执行,那么就是 “相关子查询”。

知道了 “相关子查询” 的概念之后,我们就可以回来了解 EXISTS 关键字的作用了。它的作用,就是判断子查询得到的结果集是否是一个空集,如果不是,则返回 True,如果是,则返回 False。EXISTS 本身就是 “存在” 的意思,用我们可以理解的话来说,就是如果在当前的表中存在符合条件的这样一条记录,那么返回 True,否则返回 False。

为了方便,我们再次放出这条 SQL 语句:

在这个查询中,首先会取出 Student 表中的第一条记录,得到其 Sno 列(因为在子查询中用到了)的值(如 95001),然后将该值代入到子查询中。若能找到这样的一条记录,那么说明学号为 95001 的学生选修了 1 号课程。因为能找到这样的一条记录,所以子查询的结果不为空集,那么 EXISTS 会返回 True,从而使 Student 表中的第一条记录中的 Sname 列的值被放入结果集中去。以此类推,遍历 Student 表中的所有记录后,就能得到所有选修了 1 号课程的学生的姓名。

与 EXISTS 关键字相对的是 NOT EXISTS,作用与 EXISTS 正相反,当子查询的结果为空集时,返回 True,反之返回 False。也就是所谓的 ”若不存在“。

对于下面的查询要求,只能通过 NOT EXISTS 关键字来实现,因为 SQL 中并未直接提供关系代数中的除法功能。

可以通过以下步骤的思路来实现:

STEP1:先取 Student 表中的第一个元组,得到其 Sno 列的值。
STEP2:再取 Course 表中的第一个元组,得到其 Cno 列的值。
STEP3:根据 Sno 与 Cno 的值,遍历 SC 表中的所有记录(也就是选课记录)。若对于某个 Sno 和 Cno 的值来说,在 SC 表中找不到相应的记录,则说明该 Sno 对应的学生没有选修该 Cno 对应的课程。
STEP4:对于某个学生来说,若在遍历 Course 表中所有记录(也就是所有课程)后,仍找不到任何一门他/她没有选修的课程,就说明此学生选修了全部的课程。
STEP5:将此学生放入结果元组集合中。
STEP6:回到 STEP1,取 Student 中的下一个元组。
STEP7:将所有结果元组集合显示。

根据以上思路,可以写出 SQL 语句:

其中第一个 NOT EXISTS 对应 STEP4,第二个 NOT EXISTS 对应 STEP3。

同理,对于类似的查询要求

可以使用 SQL 语句:

对于查询要求

可以使用 SQL 语句:

原文地址:https://www.cnblogs.com/kuruma/p/9562706.html

时间: 2024-10-07 19:47:38

SQL 中的 EXISTS 到底做了什么?的相关文章

SQL中if exists用法细节

用if exists建表[转] 1 判断数据库是否存在 Sql代码 if exists (select * from sys.databases where name = ’数据库名’) drop database [数据库名]  if exists (select * from sys.databases where name = ’数据库名’) drop database [数据库名] 2 判断表是否存在 Sql代码 if exists (select * from sysobjects w

sql 中的Exists 和 in

EXISTS用于检查子查询是否至少会返回一行数据,该子查询实际上并不返回任何数据,而是返回值True或False. EXISTS用于检查子查询是否至少会返回一行数据,该子查询实际上并不返回任何数据,而是返回值True或FalseEXISTS 指定一个子查询,检测 行 的存在. 语法: EXISTS subquery参数: subquery 是一个受限的 SELECT 语句 (不允许有 COMPUTE 子句和 INTO 关键字).结果类型: Boolean 如果子查询包含行,则返回 TRUE ,否

sql中not exists的用法

例子:查询物料表(tbl_material)中存在,配件主数据表(tbl_part_base_info)中不存在的配件编号: select m.part_no from tbl_material m where not exists (select * from tbl_part_base_info base where m.part_no=base.part_no );

js中的new()到底做了些什么??

要创建 Person 的新实例,必须使用 new 操作符.以这种方式调用构造函数实际上会经历以下 4个步骤:(1) 创建一个新对象:(2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象) :(3) 执行构造函数中的代码(为这个新对象添加属性) :(4) 返回新对象. new 操作符 在有上面的基础概念的介绍之后,在加上new操作符,我们就能完成传统面向对象的class + new的方式创建对象,在JavaScript中,我们将这类方式成为Pseudoclassical.基于上

SQL中IN和EXISTS用法的区别

NOT IN SELECT DISTINCT MD001 FROM BOMMD WHERE MD001 NOT IN (SELECT MC001 FROM BOMMC) NOT EXISTS,exists的用法跟in不一样,一般都需要和子表进行关联,而且关联时,需要用索引,这样就可以加快速度 select DISTINCT MD001 from BOMMD WHERE NOT EXISTS (SELECT MC001 FROM BOMMC where BOMMC.MC001 = BOMMD.MD

关于sql中in 和 exists 的效率问题,in真的效率低吗

原文: http://www.cnblogs.com/AdamLee/p/5054674.html 在网上看到很多关于sql中使用in效率低的问题,于是自己做了测试来验证是否是众人说的那样. 群众: 对于in 和 exists的区别: 如果子查询得出的结果集记录较少,主查询中的表较大且又有索引时应该用in, 反之如果外层的主查询记录较少,子查询中的表大,又有索引时使用exists.其实我们区分in和exists主要是造成了驱动顺序的改变(这是性能变化的关键),如果是exists,那么以外层表为驱

sql中exists,not exists的用法

转 sql中exists,not exists的用法 exists : 强调的是是否返回结果集,不要求知道返回什么, 比如:  select name from student where sex = 'm' and mark exists(select 1 from grade where ...) ,只要exists引导的子句有结果集返回,那么exists这个条件就算成立了,大家注意返回的字段始终为1,如果改成"select 2 from grade where ...",那么返回

SQL中in和exists的用法和效率区别

1. sql中in和exists的区别效率问题 2. SQL中IN和EXISTS用法的区别

SQL中EXISTS怎么用[转]

SQL中EXISTS怎么用 1 2 3 4 分步阅读 EXISTS用于检查子查询是否至少会返回一行数据,该子查询实际上并不返回任何数据,而是返回值True或False 方法/步骤 1 EXISTS用于检查子查询是否至少会返回一行数据,该子查询实际上并不返回任何数据,而是返回值True或FalseEXISTS 指定一个子查询,检测 行 的存在. 语法: EXISTS subquery参数: subquery 是一个受限的 SELECT 语句 (不允许有 COMPUTE 子句和 INTO 关键字).