玖叶教程网

前端编程开发入门

数据库系统原理:相关子咨询

SQL命令包括数据定义、查询、操纵和控制四大类,其中数据查询是数据库的核心操作。SQL语言允许多层嵌套查询。

嵌套查询可以使用户用多个简单的查询构成复杂的查询,增强SQL的查询能力。嵌套查询有两种形式:相关子查询和不相关子查询。

子查询可分成不相关子查询和相关子查询两类。

子查询的查询条件不依赖于父查询,这类子查询称为不相关子查询(一般子查询),不相关子查询一般使用谓词in。

子查询的查询条件依赖于外层父查询的某个属性值,称这类查询为相关子查询。相关子查询一般使用谓词exists。

首先学习SQL的相关子查询的用法。

一、相关子查询的一般用法

相关子查询:子查询的查询条件依赖于外层父查询的某个属性值。

相关子查询一般使用谓词exists。

例1:查询有一门课程成绩等于95分的学号和姓名。

(1)采用多表等值连接实现

Select S.sno,sname

From S, SC

Where S.sno=SC.sno and grade=95

该查询可以使用多表连接来实现,成绩在SC表中、学生的姓名在S表中,所以“FROM”子句中给出S表、SC表,两张表有一个连接条件即“S表的学号等于SC表的学号”、一个选择条件即“成绩是95” ,投影的是学生的学号和姓名。

(2)采用相关子查询实现

Select sno,sname

from S

Where exists

(Select *

From SC

Where S.sno=SC.sno and grade = 95)

相关子查询中使用了谓词“exists” ,它相当于是一个判别函数,也可以把它翻译成存在。

外层的查询是在S表中去查找学生的学号和姓名,但是并不是所有的学生的学号和姓名都被输出,需要进行进一步的判别。那么,某一个学生的信息是否被输出,取决于内层的查询,也就是说在SC表中要看是否存在“同一个学生SC表中的学号要等于外层的S表的学号、同一个学生选了一门课的成绩是95”,如果存在这样的记录的话,该函数“exists”返回“逻辑真”,从而该生的记录被输出。

在这里面可以看到,由于相关子查询只关心是否存在,而不关心具体返回的数据,因此在使用时内查询的“SELSEC”后面用的是“*” ,并没有举出具体的数据,不需要给出列名。

相关子查询的主要的特点:

1.相关子查询中的子查询不能独立运行;(内部的子查询不能独立运行,因为它涉及到外层的属性值。)

2.子查询多次运行;(子查询的运行次数取决于外层查询的表中的的记录条数,即外层查询的表中的每一条数据都要进行内层的查询。)

3.相关子查询的执行顺序是先执行外查询,再执行内查询。

相关子查询的执行过程:(以例1为例)

首先取外层查询中表S的第1个元组,根据它与内层查询相关的属性值处理内层查询;

若查询结果非空,则Where子句返回真,取此元组放入结果表中;(如果查询结果为空,意味着没有找到符合条件的属性值,意味着访问了整张表内查询的Where子句返回假,该记录不会放入结果表中。)

然后取外层查询中表S的下一个元组,重复上述过程,直到外层查询中表S全部检索完为止。

从上述内容可以看出,相关子查询的执行的过程类似于连接查询的执行的过程。而从这个过程中可以得出结论:在SQL中,相关子查询是最容易出错和最复杂的。因为相关子查询的复杂性在于它的内外层的相关性不容易被理解、不易存储。

二、全称量词的实现(在SQL中使用相关子查询实现全称量词的方法)

在相关子查询中,使用的谓词是EXISTS。

EXISTS代表存在量词 彐。带有EXISTS谓词的子查询不返回任何数据,只产生逻辑真值“true”或逻辑假值“false”。若子查询结果为非空,则父查询的WHERE子句返回真值,否则,返回假值。用法:

[not]exists(<子查询>) (判别存在/[not]判别不存在)(如果加上否定以后,当子查询的结果为空的时候,则返回真,否则返回假)

SQL语言中没有提供全称量词,表达全部或者是至少等语义比较困难,有时候需要元组演算来表达,然后再转换成SQL。但一般来说,可以把带有全称量词的谓词转换成等价的带有存在量词的谓词,用相关子查询来实现全称量词。

如上图所示,例如,对于所有的x均满足P就等价于不存在x不满足P。将全称量词用双层的否定表示。

例2:检索选修全部课程的学生姓名。(相当于查询这样的学生,没有一门课是他不选的。)

Select sname From S

Where not exists

(Select* From C

Where not exists

(Select * From SC

Where S.sno=SC.sno and SC.cno=C.cno));

在例2的SQL查询中,将全称量词用双重的否定来表示。最外层是S表,在S表中,获得学生的姓名;需要进行“不存在”测试,在中间层是C表中进行;最内层是SC表,在SC表中,SC表的学号要等于S表中的学号、SC表的课程号要等于C表的课程号。

内查询表达的是在课程表C表中去查找、判断这门课是否被S表中的某个学生选择,即内层查询表达的是S表中的某一个学生没选的课,如果S表中某一个学生没选的课为空,就是所有课程全都选了,然后测试的结果返回条件为真,该生被输出。

所以,将一个全称量词通过双层的否定存在的量词来实现该查询。

例3:检索所学课程包含学生s3所学全部课程的学生学号。

将该语义中的全称量词用存在量词来表示:

对于所有的y,P满足的话,Q一定满足;等价于不存在y,P满足但是Q不满足。

对于例3而言,相当于该语义查询学生X,对所有课程Y,只要s3选修了课程Y,则学生X也选修了Y。即不存在有些课程s3选了,但该生没选。

Select distinct X.sno

From SC as X

Where not exists

(Select*

From SC as Y

Where Y.sno= 's3' and not exists

( Select* From SC as Z

Where Z.sno=X.sno and Z.cno=Y.cno))

使用双层否定表达全称量词。由于例3只涉及到学生的学号,因此只需要表SC一张表就可以表示了。最外层的表SC起别名X,中间层的表SC起名为Y,最内层的表SC起名为Z。输出的是最外层的表SC即X的学号;中间应该是学生s3选择的课,所以条件放在中间层;最内层是Z的学号等于X的学号、Z的课程号等于Y的课程号。

内层查询实现的是查找学生s3选了但是该生没选的课。如果这个判断为空,那么不存在“学生s3选了但是该生没选的课”,那么返回为真,该生被输出,也就意味着不存在“学生s3选了但是该生没选的课”,就是该生选了全部课程,获得了正确的结果。

相关子查询的难点在于它的内外层的相关性不容易理解、使用时容易出错。

三、总结

SQL语言允许使用多层嵌套查询构成复杂的查询,从而增强SQL的查询能力。嵌套查询也是SQL中结构化的含义所在。同一查询任务,可以使用连接查询、不相关子查询和相关子查询来完成。

连接查询一定能用不相关子查询(IN)实现,一般形式的子查询(即不相关子查询)都能用相关子查询(EXISTS)实现。

相关子查询不一定能被其他形式的子查询等价替换,不相关子查询不一定能转化为多表的连接查询。

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言