select语句多表联合查询(四)上

版权声明:未经博主允许请勿转载 https://blog.csdn.net/hlz_12345/article/details/84997753

(所有表都在select语句多表联合查询(一)中)

  (not) exists子查询

1.如何理解exists操作?

2.何时用exists

课程里说exists的语义为子查询结果中有无元组存在。而且exists前面是没有属性与子查询的结果属性相对应的(仔细想想前面的in和θsome,Θall),既然这样,我们也就没有必要对select的结果属性进行限制,所以exists还是有点特殊的。好,接下来有个问题就是exists既然是来检测子查询的结果中有无元组存在,那么如果有,我们知道它会返回给上一层的查询一个true值,可是这跟上一层的查询是没有关系的,比如我们随便写个查询语句

select Sname from Student where exists(select * from Student where Sage > 19);

这句话的执行结果把student表里所以名字都显示了。子查询是找出在student表里年龄大于19的同学信息,那根据我们的表可以知道张三张四,王三王思都是年龄大于19的同学,所以子查询语句总会返回true值,然后我遍历student表力的每个元组并检测exists子查询返回的结果是否为真(在这个例子里当然都为真),所以会显示表里所有的名字。

所以我猜想exists这个操作的设计就是基于相关子查询的,并且是让程序员写(这就有点骚了)。如果是非相关,就像我上面写的那条语句(虽然外层查询和子查询都是student表,但内外不相关),那就没有意义。好,我写上面那条查询语句的本意是找出student表里年龄大于19的学生姓名,那么如何正确地用exists子查询表达?

假设是相关子查询,那么应该是这样的:我们要把student表在两个查询中重新命名,然后在子查询中令两个表的S#相等。这样我们就将两表“相关”了,然后我们来看下相关后是否就使得这样的查询有意义了呢?试用上一篇相关子查询的思路,从外层的第一个元组开始,拿该元组的S#进入到内层查询,从内层查询的第一个元组到最后一个,将两S#进行比对,如果相等,再看内层表的年龄是否大于19,如果大于,就返回true,并将外层当前的元组按照select的属性输出,即输出Sname。

select Sname from Student S1 where exists(select * from Student S2 where S1.S# = S2.S# and S2.Sage > 19);

但我又想到了一个问题,上面这种情况是内层只会返回一个true的元组,如果内层返回多个true呢,当前Sname是否会重复输出?于是我又想了一个例子:查询选修了课程的学生姓名。

扫描二维码关注公众号,回复: 6749354 查看本文章

select Sname from Student where exists(select * from SC where Student.S# = SC.S#);

事实证明,Sname是不会重复输出的,这意味着,只要在子查询中存在满足select条件的元组,就会输出当前外层查询的select的东西。这也可以解释为什么第一条语句会输出所有名字了。

我又想了想,觉得根本不会出现多个true的情况,因为存在的意思是只要有一个出现。那么在内层查询中只要找到一个满足条件的元组,自然就break,而不是continue,然后返回给上一层true,上一层知道是true后就把当前select的属性输出了。

分析至此,我们可以写题目了。

示例一:检索选修了赵三老师主讲课程的所有同学的姓名。

赵三来自Teacher,老师讲哪些课程来自Course,同学选了哪些课来自SC,姓名来自Student。

select Sname from Student where exists(select * from Teacher,Course,SC where Teacher.T# = Course.T# and Course.C# = SC.C# and Student.S# =SC.S# and Tname = '赵三');

我们主要抓住一点就是只要这个学生选修了赵三老师的任意一门课(exists),我们就输出这个学生的姓名。

示例二:检索有一门及以上课程不及格的同学的姓名

同理,要抓的点是,只要这个同学有任意一门课程小于60分,我们就输出这个学生的姓名。

select Sname from Student where exists(select * from SC where Student.S# =SC.S# and Score < 60);

 

总结与归纳:

1.exists子查询是比较特殊的子查询,它不需要对select的结果属性进行限制,所以可以是*

2.一般情况下exists子查询是相关子查询,它的where条件里总会与外层查询的表有关

3.因为“exists”是一旦找到满足条件的元组马上break然后返回true给外层,所以对于外层查询的当前具体属性值不可能输出多次。

(当然,如果在结果表中出现了重复的结果,那只能说明你原来那个外查询的表中就存在着重复的属性值)

4.exists通常用于“只要。。。找到(有,选修,反正是个动词)一个任意的。。。就输出。。。”这种情况

 

 

 

 


 

 

猜你喜欢

转载自blog.csdn.net/hlz_12345/article/details/84997753