From XA01 As A,XA01 As B, TB03 Where A.XA0114=TB0301 And
A.XA0114=B.XA0114 And
B.XA0102='100022101' 查询结果如图5-9所示。
图5-9 用嵌套子查询或自连接查询查找同班同学的信息
2.In运算符子查询
(1)查询方式:父查询字段表达式与子查询结果用In进行集合比较,即用In运算符判断父查询的字段表达式值是否属于子查询集合,将属于集合的记录添加到父查询结果记录集中去。
(2)使用条件:子查询必须返回1条或多条单字段记录值。
由于在嵌套查询中,子查询的结果往往是一个集合,所以谓词In是嵌套查询中最经常使用的谓词。
【例5-23】 用In子查询,查询与“周明明”同班同学的信息(学号、姓名与班级名)。 由于姓名为“周明明”的同学可能不惟一,即子查询“周明明”所在班级记录可能有多个,因此该查询要用In子查询来实现。
Use Xsgl
Select TB0302 As '班级名称',XA0102 As '学号',XA0104 As '姓名' From XA01
Join TB03 On XA0114=TB0301 Where XA0114 In ( Select XA0114
From XA01
Where XA0104='周明明')
- 156 -
语句执行后查询结果如图5-10所示,在图中可以看到,在学生档案XA01中到少有两个周明明,分别出现在机制30031班与模具30031班。
图5-10 用In子查询查找周明明同班同学的信息
3.Any与All子查询
当子查询中返回单值时可以使用比较运算符,而当子查询中返回多值时就不能单独使用比较运算符,此时可使用<关系运算符> 或 <关系运算符> 组合运算符。
(1)查询表达式格式
<字段> <关系运算符> (Select 子查询) <字段> <关系运算符> (Select 子查询) 其中,关系运算符为:>、>=、=、<、<=。 (2)查询方式
>Any :当字段值>子查询结果某一个值时,查询表达式为True <关系运算符>Any =Any :当字段值=子查询结果某一个值时,查询表达式为True
>All :当字段值>子查询结果所有值时,查询表达式为True <关系运算符>All =All :当字段值=子查询结果所有值时,查询表达式为True
(3)使用条件:子查询为单字段多值集合。
【例5-24】利用“=Any”子查询,查询与“周明明”同班同学的信息(学号、姓名与班级名)。
Use Xsgl
Select TB0302 As '班级名称',XA0102 As '学号',XA0104 As '姓名'
- 157 -
From XA01
Join TB03 On XA0114=TB0301 Where XA0114 =Any (Select XA0114
From XA01
Where XA0104='周明明')
执行语句的结果如图5-10所示,从语句执行效果来看,“=Any”子查询与In子查询是相同的。由此可见,同一个查询问题可以用不同的语句完成。
5.1.6 相关子查询
1.相关子查询的处理过程
相关子查询与前面的嵌套子查询有一个明显区别,子查询的查询条件依赖于外部父查询的某个属性值。求解相关子查询不能象求解嵌套子查询那样,一次将子查询求解出来,然后求解外部查询。相关子查询的子查询由于与外部查询有关,因此必须反复求值。从概念上讲,相关子查询的一般处理过程如下:
(1)首先取外部查询中的第一个记录,根据它与子查询相关的属性值处理内层查询; (2)若Where子句返回值为真(即子查询结果非空),则取此记录放入结果表; (3)然后再检查外部表的下一个记录;重复这一过程,直至外部表全部检查完毕为止。 【例5-25】假如在成绩表中有如表5-6所示的几条记录,编写下列查询语句对嵌套子查询与相关子查询进行对比分析。
表5-6 学生成绩表tblScore的记录
Stud_Id(学号) 101100101 101100101 101100101 101100102 101100102 101100102 Course_Id(课程名 ) 00001 00002 00003 00001 00002 00003 Score(成绩) 70 80 65 95 63 77 (1)查询考试成绩大于所有同学平均考试成绩的成绩记录。 这道题目属于嵌套子查询,查询语句如下: Use Studentsys
Select Stud_Id , Course_Id , Score From tblScore
Where Score>(Select Avg(Score) From tblScore)
- 158 -
查询过程可简要描述如下:先从子查询中查询出所有学生的平均成绩,将该结果作为父查询的查询条件,再从父查询中查询出大于所有同学平均考试成绩的成绩记录。
(2)查询考试成绩大于该同学平均考试成绩的成绩记录。
两位学生三门课程平均成绩分别是72与78。题目中希望得到的结果是:
Stud_Id 101100101 101100102 Course_Id 00002 00001 Score 80 95 这道题目就是相关子查询,查询语句如下: Use Studentsys
Select Stud_Id , Course_Id , Score From tblScore C1
Where Score>(Select Avg(Score) From tblScore C2
Where C1.Stud_Id=C2.Stud_Id)
查询过程可简要描述如下:先从父查询学生成绩表的第1条记录开始,通过子查询的连接表达式C1.Stud_Id=C2.Stud_Id(将别名为C1与C2两个学生成绩表tblScore作自连接)作内层查询,得到该同学的平均成绩;通过Where子句判断第1条记录是否满足查询条件(成绩大于该同学平均考试成绩),满足条件则显示记录,否则不显示;然后再检查父查询表的下一个记录,重复这一过程,直至父查询表全部检查完毕为止。
通过前面2个例子,可以总结出相关子查询的本质是父查询和子查询有相关性,即在子查询中出现了父查询的字段值。
2.Exists运算符子查询
Exists运算符子查询是相关子查询的一个典型应用。用Exists判断子查询结果是否为空。若为非空,则Exists返回逻辑值True,否则返回False。
【例5-26】 在学生管理数据库Xsgl中,利用Exists子查询,查询与“周明明”同班同学的信息(学号、姓名与班级名)。
Use Xsgl
Select XA0102,XA0104,TB0302 From XA01 As A
Join TB03 On XA0114=TB0301
Where Exists (Select * From XA01 As B
- 159 -
Where A.XA0114=B.XA0114 And B.XA0104='周明明')
说明:
(1)因为Exists子查询只返回真值或假值,给出列名亦无实际意义,所以Exists子查询的列名常用“*”表示。
(2)查询过程可简要描述如下:在子查询中通过连接表达式A.XA0114=B.XA0114,将别名为A与B两个学生档案表XA01作自连接。先从父查询中XA01 A表第1条记录开始,取出班级编码A.XA0114,通过子查询中的自连接表达式A.XA0114=B.XA0114找到子查询中XA01 B表同班学生的记录,并通过条件表达式B.XA0104='周明明' 判断该班同学中是否存'周明明',若存在则子查询结果非空,Exists判断为真,此时应将父查询中XA01 A表中当前记录添加到与'周明明'同班同学的集合中去。然后再对XA01 A表中第2 条记录作上述处理,直到最后一条记录为止。
(3)Not Exists的返回结果与Exists相反。
5.1.7 数据查询综合实例
【例5-27】按下列要求编写查询语句。
(1)在班级课程表TA19中,查询周学时高于平均周学时数的课程信息(课程编码与周学时数)。
Use Xsgl
Select TA1904,TA1910 From TA19
Where TA1910 >(Select Avg(TA1910) From TA19 )
执行嵌套查询语句时,先执行子查询语句“Select Avg(TA1910) From TA19”,得到单行单列结果(如平均周学时数=4.25),然后将其作为父查询关系表达式右边常量,执行父查询“Select TA1904,TA1910 From TA19 Where TA1910>4.25”。
(2)在班级课程表TA19等表中,查询课时数高于平均课时数的课程信息。课程信息为课程编码、课程名、班级名、课程类别、课程性质、考核标志、起始周次、教学周数、周学时数和课时数,并用汉字显示标题栏。
由于投影字段涉及班级课程表TA19、课程编码表TB01、班级编码表TB03、课程类别表TC01、课程性质表TC02、考核标志表TC03,所以要对6张表通过主、外键进行内连接。课程数可通过教学周数(TA1909)*周学时数(TA1910)得到。因此,查询课时数高于平均课
- 160 -