- Oracle从新手到高手
- 杨继萍
- 2285字
- 2025-04-18 21:19:33
4.3 使用子查询
在执行数据操作的过程中,如果某个操作需要依赖于另外一个SELECT语句的结果,那么可以把SELECT语句嵌入该操纵语句中,这就形成了一个子查询。实际上,在操作表中的数据时,数据并不是孤立的,而是互相关联的。这样就可以根据数据之间的关联使用相应的子查询,从而实现复杂的查询。
4.3.1 子查询的概念
在一个SELECT语句被嵌套在另外一个SELECT、UPDATE或DELETE等SQL语句中时,被嵌套的SELECT语句就是子查询。使用子查询的原因是,希望执行某个SQL语句,但是该SQL语句还需要依赖于另外一个SELECT语句的执行结果。
例如,当要检索某一部门的员工信息时,可以连接查询EMP和DEPT表,也可以在检索EMP表时使用子查询检索DEPT表。如下的语句演示了一个子查询。

从这里可以看出,相比连接多个表的查询,子查询的使用更加灵活,且功能更强大。在执行子查询操作的语句中,子查询也称为“内查询”,包含子查询的查询语句也称为“外查询语句”。例如在上面的示例中,如下的语句为内查询:
select deptno from dept where dname='SALES'
外查询语句为:
select empno,ename,job,sal from emp
在一般情况下,外查询语句检索一行,子查询语句需要检索一遍数据,然后判断外查询语句的条件是否满足。如果条件满足,则外查询语句检索到的数据行就是结果集中的行;如果条件不满足,则外查询语句继续检索下一行数据。
在多数情况下,子查询可以使用连接查询来代替。也就是说,使用子查询完成的操作也可以使用连接查询完成。实际上,连接查询的效率也远高于子查询的效率,但是子查询更好理解,使用更灵活、方便。
在使用子查询执行操作时,应该遵循如下规则。
※ 子查询必须使用括号括起来,否则无法判断子查询语句的开始和结束。
※ 子查询中不能包括ORDER BY子句。
※ 子查询允许嵌套多层,但是最多嵌套255层。
子查询可以分为4种类型,即单行子查询、多行子查询、多列子查询和关联子查询。各种子查询的特点如下。
※ 单行子查询:子查询语句只返回单行单列的结果,即返回一个常量值。
※ 多行子查询:子查询语句返回多行单列的结果,即返回一系列值。
※ 多列子查询:子查询语句返回多列的结果。
※ 关联子查询:子查询语句引用外查询语句中的一个列或多个列,即外查询和内查询是相互关联的。
各种子查询之间还可以相互嵌套。在Oracle系统中,子查询的嵌套层数可以达到255层,但是真正嵌套255层的子查询是很少的。实际上,嵌套的层数越多,查询语句的执行效率也就越差,因此应该尽量降低子查询的嵌套层数。
4.3.2 单行子查询
在单行子查询中,该内查询只返回单行单列值,因此可以把这种子查询作为一个常量。在WHERE子句中,可以使用单行比较运算符来比较某个表达式与子查询的结果。可以使用的单行比较运算符包括等于“=”、大于“>”、大于或等于“>=”、小于“<”、小于或等于“<=”和不等于“<>/!=”。
例如,下面的语句在子查询中使用统计函数,从EMP表中得到薪金最低和薪金最高的员工信息。

在执行子查询的过程中,如果内查询的结果是空值,那么外查询的条件始终不会满足,该查询的最终结果是空值。例如,在下面的查询中,子查询语句试图查找部门名为MANAGER的信息。但是,由于在DEPT表中不存在该部门的信息,所以子查询语句的结果是空值。这样WHERE子句中的条件总为FALSE,因此该查询的最终结果也是空值。

在单行子查询中,常见的错误是在子查询中返回了多行数据或者包含了ORDER BY子句。如果在单行子查询中返回了多行数据,那么这个查询就会发生错误,系统无法正确执行该操作。
在子查询中也不能包含ORDER BY子句,如果希望对数据进行排序,那么只能在外查询语句中使用ORDER BY子句。
4.3.3 多行子查询
多行子查询可以返回单列多行的数据。在这种多行子查询中,必须使用多行运算符来判断,而不能使用单行运算符。使用多行运算符可以执行与一个或多个数据的比较操作。在Oracle系统中,可以使用的多行比较运算符包括:IN(等于列表中的任何一值)、ANY(与子查询返回的每个值进行比较)和ALL(与子查询返回的所有值进行比较)。
ANY运算符表示与子查询中的每个值进行比较。这时,需要将单行比较运算符与该运算符组合起来使用。与单行比较运算符组合之后,所使用的ANY运算符结果如下。
※ <any:表示小于最大值。
※ =any:与IN运算符等价。
※ >any:表示大于最小值。
对于ALL运算符而言,与单行比较运算符组合之后,所使用的ANY运算符结果如下。
※ <all:表示小于最小值。
※ >all:表示大于最大值。
在下面的示例,将练习使用ALL、ANY和IN运算符进行查询。
① 以SCOTT身份连接数据库。
② 在子查询的比较条件中,使用>ANY运算符查询大于MANAGER职位中最小薪金的员工信息。

③ 下面是使用IN运算符的多行子查询,用于查询属于ACCOUNTING和RESEARCH部门的员工信息。

④ 下面是使用ALL运算符的多行子查询,用于查询薪金大于所有MANAGER职位的员工信息。
SQL> select empno,ename,job,sal 2 from emp where sal >all(select sal from emp where job='MANAGER');
另外,在使用IN、ALL和ANY等多行比较运算符时,还可以使用NOT运算符,表示取反。
4.3.4 关联子查询
在前面介绍的子查询中,内查询和外查询是分开执行的,即内查询的执行与外查询的执行是没有关系的,而外查询仅使用内查询的最终结果。在子查询语句中,当内查询的执行需要借助于外查询,而外查询的执行又离不开内查询的执行时,内查询和外查询是相互关联的,这种子查询称为“关联子查询”。例如,在内层被嵌套的SELECT语句中包含了外层SELECT语句中的员工代码。这类子查询在某些情况下可能会产生一定的问题,因为内层子查询返回的记录都是外层查询所操作的候选对象,当数据量较大时,这会导致查询效率低下。
现在使用关联子查询检索某个职位的员工薪金是否超出了平均水平,所使用的查询语句如下。

在上面的查询语句中,外层查询使用关联子查询计算每个职位的平均薪金。而关联子查询必须知道每个员工的职位,以便外层查询寻找该员工的平均薪金是否高于所在部门的平均值。如果薪金高于平均薪金,则该员工的信息结果会显示出来。在执行语句的过程中,必须遍历EMP表中的每条员工记录,因此如果EMP中有许多记录,则该语句的执行速度将会异常缓慢。