数据库 EXISTS与NOT EXISTS

EXISTS与NOT EXISTS

  • EXISTS:表示存在xxx。在查询的外层添加一个EXISTS,当内层查询有结果,则该EXISTS返回true,反之返回false
  • NOT EXISTS:表示不存在xxx。在查询的外层添加一个NOT EXISTS,当内层查询有结果,则该NOT EXISTS返回false,反之返回true
##表生成的过程 ``` SELECT Sname FROM Student WHERE NOT EXISTS(1) (SELECT * FROM Course WHERE NOT EXISTS(2) (SELECT * FROM SC WHERE Sno= Student.Sno AND Cno= Course.Cno)); ``` ###学生表 ![](http://images2015.cnblogs.com/blog/1017814/201704/1017814-20170422154233899-361931250.png) ###课程表 ![](http://images2015.cnblogs.com/blog/1017814/201704/1017814-20170422154308962-74150998.png) ###学生选课表 ![](http://images2015.cnblogs.com/blog/1017814/201704/1017814-20170422154327915-791639455.png)

以上面的为例:首先改例子中有两个EXISTS,我们先从最里面的内容开始,当一个元组和课程表中的第一个元组在最里层循环中与SC.sno和SC.cno进行匹配的时候。

(情况1)若配上最内层的WHERE将该数据插入到临时表中,第一个NOT EXISTS(指内层的NOT EXISTS,代码中的(2))判断该临时表不为空则返回false。

(情况2)若没有匹配上最内层的WHERE返回false,则不将数据插入到临时的表中,第一个NOT EXISTS(是内层的NOT EXISTS,代码中的(2))判断结果表为空返回true


####当Course循环结束之后 ####第二个NOT EXISTS(最外层的NOT EXISTS,代码上的(1))判断该内层返回集是否为空。
####(1)若为内层的NOT EXISTS返回true,WHERE接收到true之后将数据插入临时的结果集中,第二个NOT EXISTS判断临时表不为空,则返回false,不将内容添加到最终的结果集中。
####(2)若为内层的NOT EXISTS返回false,WHERE接收到false之后不将数据插入到临时的结果集中,第二个NOT EXISTS判断临时表为空,则返回true,将内容添加到最终的结果集中。
####本人的语言表达能力不足,要是上面的内容没有看明白的话,一下是我总结的方法:
####WHERE语句是当判断的结果为true的时候,将内容添加到结果集中,若为false的话,则不讲内容添加到结果集中。
####EXISTS是当查询的表为非空的时候则返回true,当查询的表为空的时候返回false。 ####NOT EXISTS则是当查询的表为空的时候返回true,当查询的表为非空的时候返回false。
``` //查询选择了全部课程的学生的查询语句 SELECT Sno FROM Student s WHERE NOT EXIXTS( SELECT * FROM Course c WHERE NOT EXISTS( SELECT * FROM SC sc WHERE sc.sno = s.sno AND sc.cno = c.cno
        // 该查询内部,每次查询从学生表(sno)和课程表(cno)中获取一条数据
        // 与学生选课表中的所有数据逐条比较,将符合条件的数据列出来
        //假如查询结果有数据,Not Exists则返回false,Course表中则不添加该课程数据
        //假如查询结果没有数据,Not Exists则返回true,Couse表中则添加添加该课程数据
        //在Exists或Not Exists进行嵌套使用,相当于for循环进行嵌套使用。
    )
);
个人的理解:其中外层的Student与次外层的Course的组合分别与SC中的内容进程比较,将符合要求的内容进行保留
可以通过以下步骤的思路来实现:

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


###<font color="red">若没有听明白的话可以通过上面的方法进行推到来得出自己的观点</font>

##<font color="red">补充的内容</font>
####上述就涉及到SQL的不相关子查询与相关子查询
select Sno
From SC
Where Cno in (
    select Cno
    From Course
    Where Cname = '数据结构'
)
###首先通过子查询得到课名为“数据结构”的课程的课号,然后遍历SC(选课)表中的每一条选课记录,若当前这条记录的课号为"数据结构"这门课的课号,则将这条记录的Sno列的值放到结果集里面去,最终我们可以得到所有选修了“数据结构”这门课的学生的学号。

###这种类型的的查询是先执行子查询,得到一个集合(或值),然后将这个集合(或值)作为一个常量带入到父查询的Where子句中去。如果单纯地执行子查询,也可以成功的。这种类型的查询,叫做“不相关子查询”
#查询每个学生查过他选修的所有课程的平均成绩的课程的课程号
SELECT AVG(Grade)
From sc
WHERE Sno = ?
###Sno = ?的位置应该是不断地将Student表中的每一条记录中的Sno列的值代入此处,然后求出该Sno对应的平均成绩。我们需要的是输入一些列的值,然后得到一系列对应的输出。这个时候,我们就要用到另一种嵌套查询,叫做“相关子查询”。相关子查询的意思就是<font color="red">子查询中需要用到父查询中的值</font>。

###判断是否是“相关子查询”,只要子查询不能脱离父查询单独执行,那么就是“相关子查询”。
原文地址:https://www.cnblogs.com/gxcstyle/p/6747863.html