设为首页 收藏本站
查看: 1156|回复: 0

[经验分享] Oracle中含EXISTS查询语句分析

[复制链接]

尚未签到

发表于 2018-9-24 11:46:07 | 显示全部楼层 |阅读模式
  刚学数据库,就拿课本《数据库系统概论(第四版)》中的例题说事吧。
  先看下面三个表:
  Student表:
  学号 姓名    性别  年龄 系别
  SNO     SNAME               SSEX     SAGE SDEPT
  --------- ------------------------ -------------- --- --------
  200215121 李勇                 男         20 CS
  200215122 刘晨                 女         19 CS
  200215123 王敏                 女         18 MA
  200215124 徐明                 男         17 EN
  200215125 张立                 男         19 IS
  200215126 李鹏                 男         20 EN
  200215127 王飞                 男         19 IS
  Course表:
  课号  课程名      先修课   学分
  CNO  CNAME                           CPNO    CCREDIT
  ---- ---------------------------------------- ---- ----------
  2    数学                                    2
  6    数据处理                               2
  7    PASCAL语言                          6               4
  5    数据结构                               7               4
  1    数据库                                  5               4
  3    信息系统                               1               4
  4    操作系统                               7               4
  SC表(学生选课表):
  学号  课程号  分数
  SNO       CNO       GRADE
  --------- ---- ----------
  200215121 1            92
  200215121 2            85
  200215121 3            88
  200215122 2            90
  200215122 3            80
  200215127 2            99
  200215125 3            49
  下面进入正题:
  一、查询学号为200215121的学生选修的所有课程:
  至少有三种方法:
  (1)
  SQL> select SC.CNO,CNAME from Course,SC where
  Sno=200215121 and SC.Cno=Course.Cno;
  (2)
  SQL> select CNO,CNAME from Course where Cno in
  (select Cno from SC
  where Sno=200215121 and Cno=Course.Cno);
  (3)
  SQL> select CNO,CNAME from Course where exists
  (select * from SC
  where Sno=200215121 and Cno=Course.Cno);
  经验证,以上四种查询返回结果都是:
  CNO  CNAME
  ---- ----------------------------------------
  1    数据库
  2    数学
  3    信息系统
  第一、二个查询还好理解,第三个就有些抽象了,exists是什么意思呢?
  看下面的问题:
  查询学号为200215121的学生没有选修的所有课程
  SQL语句为
  SQL> select CNO,CNAME from Course where not exists
  2  (select * from SC
  3   where Sno=200215121
  4   and Cno=Course.Cno);
  结果:
  CNO  CNAME
  ---- -----------------------------
  6    数据处理
  5    数据结构
  4    操作系统
  7    PASCAL语言
  经过多次查询,发现以下规律:
  1) 当CNO为6、5、4、7时子查询结果都为空。
  2) 当CNO为6、5、4、7时查询结果都为全集。
  3) 当CNO不为6、5、4、7时查询结果都为空,但子查询结果都不为空。
  可以看到,Course元组与SC元组并无直接关联,那么外层查询与内层查询是如何
  联系起来的呢?通过以上规律发现,只有当子查询返回空时,外层查询(即整个查询)
  才会返回非空值,但为什么总是返回全集呢?我们不防这样理解:内层查询返回空可
  看作“假”,即false,因为EXISTS量词只关心子查询是否有返回值,当有返回值时,EXISTS
  返回真,那么not exists (true) 返回假,所以not exists (false) 结果就是真,这样一来,
  not exists (false)  true,整个查询语句等价于:select  CNO,CNAME from Course where
  true ! 这回恍然大悟,不就是一个简单投影嘛!
  exists是相关子查询,特别要注意连接的问题,看以下语句(可以跳过):
  SQL> select Sname from Student where not exists
  2  (select * from Course where Cno=9999);
  SNAME
  --------------------
  李勇
  刘晨
  王敏
  徐明
  张立
  李鹏
  王飞
  已选择7行。
  有有认为上面语句的含义是:查询未选修课程号为9999的课程的学生姓名,因为根本就没有该课程,
  当然所有的学生都进结果集。
  看似理所当然吧,呵呵,如何你这样想,那就大错特错了!
  为了对比一下,请再看下面的查询:
  SQL> select Sname from Student where not exists
  2  (select * from Course where Cno=3);
  未选定行。
  可以验证,只要Cno值存在,返回结果总为空。
  如果按上面的理解,该语句的含义是:查询未选修课程号为3的课程的学生姓名。
  假如依照查询结果判断,既然返回为空,难道是每个学生都选了Cno为3的课程吗?当然不是!
  细心一看才知道,原来子查询返回的元组与父查询表的元组根本就没有包含关系!这当然就没有可比性了,虽然子查询(select * from Course where Cno=3)返回结果不为空,但由于未和外层查询连接形成笛卡尔积,这时where条件好比是在判断两个不同性质的集合是否存在从属关系一样,回答当然是NO!
  难道这样我们就把问题解决了吗?上面只是针对Cno的某个具体值而探讨,这还不能
  解释为什么整个循环完成后返回的却不是全集,看来真的是遇到难题了,想了好久,后来
  从书上看到说“所有带有IN谓词、比较运算符、ANY和ALL谓词的子查询都能用带EXISTS谓词的
  子查询等价替换”,于是发现,not exists XXX 不就是 not in XXX 吗?感觉像是管中窥豹,
  这样细微一变,让我突然对整个语句的内部执行过程有了点想法:既然子查询为空时返回
  全集,当然要找子查询不为空的元组了!于是慢慢思考,认为应该是这样:外层查询每次
  取Course元组的一个Cno给内层查询,内层查询执行查询语句,若结果不为空(即学号为
  200215121的学生选修了该Cno对应的课程),则放入内层查询结果集中,注意这时并不执行
  外层查询,而是继续取下一个Course元组的一个Cno给内层查询,仍然执行内层查询,直到
  遍历所有Course元组后,内层查询结束。此时内层查询的结果集里不是一个元组,而是三个!
  它恰恰包含了学号为200215121的学生选修了的所有课程...哈哈,真相大白了...整个语句至此
  变为
  select CNO,CNAME from Course where not exists (  ,  ,  );
  哇,这不就是
  select CNO,CNAME from Course where  not in (  ,  ,  );
  吗?
  好了,问题解决,可以吃饭去了~~
  想一想,查询所有学生都未选修的课程,SQL语句该怎样写呢?


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-600568-1-1.html 上篇帖子: oracle 10g 数据泵导入导出 下篇帖子: Oracle技术之11.2 RAC时间同步异常(一)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表