读懂,查询选修了全部课程的学生姓名

自己蒙着脑袋想百思却也不得其解,侥幸找到一些参考,特此记录分享。

参考书籍,原书封面置于文后

《数据库系统概论》萨师煊       P108,例3.62

《数据库系统概念》                  P51

读懂的关键在于正确理解 not exists,是从集合的角度,而非单一记录。

我们先假定一个简单的场景:

sno为'1'的学生,在三门课程中,选修了cno为‘2’,‘3’的两门课程,单单没有选修cno ‘1’

sno        cno

1           1             ×

1           2             √

1           3             √

读懂,查询选修了全部课程的学生姓名

    《数据库系统概论》,P108

 根据假定的场景,先从Student表中取第一条元组,将sno ‘1’送入内层查询块。由于sno‘1’与cno'1'的组合不在选课表SC中,内层查询块返还结果为空 null,即false。

where Not EXISTS false(单一布尔值,直接取反),相当于 where true。导致sno '1' 被筛选出。

我们用同样的思路来分析《数据库系统概论》萨师煊   P108 例3.62

读懂,查询选修了全部课程的学生姓名

这里涉及到三张表,Student(sno)、Course(cno)、SC(sno,cno),最内层的查询块,给出了这三张表的连接条件:where SC.sno = Student.sno  and SC.cno = Course.cno; 是将选课表SC与学生表Student做笛卡尔积,得到sno的学生信息,将选课表SC与课程表Course作笛卡尔积,得到cno的课程信息。

同样根据假定的场景,从Student表中取第一条元组,sno ‘1’被送入内层查询块。我们理解的执行过程是,从Student表中取sno ‘1’,从Course表中取cno '1',送入最内层的查询块,在SC表中没有这样一条记录,where SC.sno = Student.sno  and SC.cno = Course.cno 的结果肯定是 false

两次not exists,得到的结果仍然是false,导致sno '1'不被输出。与它没选修cno ‘1’事实相符。

为什么错,这就是在从单一记录的角度理解 not exists。代码最神奇的地方在于,几乎看不出有集合的痕迹,却实现了与全体课程作比较(在我自己的代码中,通过聚集函数count(*),将集合转化成了数字)。

将错进行到底,就能明白思路中确实存在着问题。

sno ‘1’被送了入内层查询块,继续从Course表中取cno '2',送入最内层的查询块,在SC表中有这样一条记录,where SC.sno = Student.sno  and SC.cno = Course.cno 的结果为 true

两次not exists,得到的结果仍然是true,导致这时 sno '1'被输出。

同样的思路,sno '1' 和 cno '3'时,会导致sno '1'又一次被输出。

这里强调一下,要从集合的角度理解not exists。这行代码中的not exists一共出现了两次,它们针对的对象并不都是单一的布尔值。第二个not exists面对的场景比较单纯,最内层查询块处理的只是一个学号跟一个课程号,看看选课表里有没有,有就返还一个布尔值true,没有就给一个布尔值

false,第二个not exists我只要把这个布尔值取反就是逻辑正确。第一个not exists,是sno ‘1’ 的,等待它是三个布尔值。有内层查询块处理cno '1'得到的true,处理cno '2'和cno ‘3’得到的两个false。只有内层查询得到的全都是false的时候,才并成一个false,由第一个not exists取反得真,将该名学生输出。也就是该学号与每一门课程组合,去SC表里面找,每一个组合都能够找到,最内层查询块返还的结果都是true。所以机关在于,not exists对这些布尔值的运算应该是 b1 || b2 || b3,是或的关系,有一个真就是真。翻译翻译就是,在我的最内层查询块中,我从Course表中逐个拿cno,跟sno一起到SC表送检,一旦捕捉到有一个cno,SC表中没有,吐出一个false(即连接条件是where false,经内层查询块中的第二个not exists取反即得true),该学生得强行输出(true),它没有选修全部课程。只有全假才是假,即该生与每一门课的送检,都在SC表中找到,这才被丢掉,不进入输出名单。

辅助资料: 《数据库系统概念》原书 P51

读懂,查询选修了全部课程的学生姓名

关于全称命题和特称命题的补充

全称命题:对每一个,命题p(x)都成立。它的否定是:存在一个,使命题不成立。非,取反,两次取反得它本身。与或非,逻辑运算,也称布尔运算。

人教版高中数学选修2-1  P24

读懂,查询选修了全部课程的学生姓名

参考书籍封面 

读懂,查询选修了全部课程的学生姓名

读懂,查询选修了全部课程的学生姓名

上一篇:Redis命令:SETNX key value(SET if Not eXists)


下一篇:文件 I/O fs:readFile/writeFile/stat/isDirectory/isFile/readdir/mkdir/exists