一个select-from-where语句称为一个查询块。将一个查询块嵌套在另一个查询块的where子句或having短语的条件中的查询称为嵌套查询。

SQL语言允许多层嵌套,子查询的select语句中不能使用order by字句,order by只能对最终查询结果进行排序。

带有 in 谓词的子查询

判断某个属性列值是否在子查询结果中出现。由于在嵌套查询中,子查询结果往往是一个集合,所以谓词 in 是嵌套查询中常用的谓词。如果子查询结果只有一个元组,可以用=替代in

  • 查询与李明同一部门的读者
select *
from 读者
where 所在部门 in
(
	select 所在部门 from 读者
      where 读者姓名='李明'
)

带有比较运算符的子查询

父查询与子查询之间用比较运算符进行连接。当用户能确切知道内存查询返回的是单值时,可以使用比较运算符。

子查询一定要跟在比较运算符之后。

  • 查询年龄比“李明”大的读者的姓名
select 读者姓名
from 读者
where 出生年月 < 
(
	select 出生日期 from 读者
      where 读者姓名 = '李明'
)

本例为不相关查询,内外层查询没有联系。

  • 查询每位主编超过他编写图书平均单价的图书名称和主编
select 图书名称, 主编
from 图书 x
where 单价 >= 
(
	select avg(单价)
      from 图书 y
      where y.主编=x.主编
)

本例中子查询的查询条件依赖于父查询,因此是相关子查询。x是表图书的别名,又称为元组变量,可以用来表示图书的一个元组。

上述代码的一种可能执行过程是:

  1. 从外层查询中取出一个元组x,将元组x的主编值(假设为莫言)传递给内层查询。
select avg(单价)
from 图书 y
where y.主编='莫言'
  1. 执行内层查询,得到一个单值(假设为32.3),用这个值代替内层查询,得到外层查询。
select 图书名称, 主编
from 图书 x
where 单价 >= 32.3

假设该查询得到的结果为(《红树林》, 莫言)

  1. 外层查询取下一个元组重复上述步骤,知道外层的图书表中元组全部处理完毕。

带有any或all谓词的子查询

子查询返回单值时可以用比较运算符,但返回多值时要用anyall谓词修饰符,而且必须同时使用比较运算符。

  • 查询其他出版社中比清华大学出版社某一本图书单价低的图书名称和单价
select 图书名称, 单价
from 图书
where 出版社 <> '清华大学出版社' and 
	单价 < any
	(
    	    select 单价 from 图书
          where 出版社 = '清华大学出版社'
      )
  • 查询其他出版社中比清华大学出版社所有图书单价都低的图书名称和单价
select 图书名称, 单价
from 图书
where 出版社 <> '清华大学出版社' and 
	单价 < all
	(
    	    select 单价 from 图书
          where 出版社 = '清华大学出版社'
      )

带有exists谓词的子查询

带有exists谓词的子查询不返回任何数据,当子查询结果集非空返回逻辑值 true,当子查询结果集为空返回逻辑值 falsenot exists反之。

带有exists的子查询只返回真值或假值,给出列名无实际意义。所以,其目标列的通常使用*

  • 查询所有借阅了A002号图书的读者姓名
select 读者姓名
from 读者
where exists
(
	select * from 借阅
      where 读者编号=读者.读者编号  -- 相关子查询
    	and 图书号='A002'
)
  • 查询和李明同一天出生的读者
select *
from 读者 d1
where exists
(
	select *
      from 读者 d2
      where d1.出生日期=d2.出生日期 and d2.读者姓名='李明'
)

等价于:

select *
from 读者
where 出生日期=
(
	select 出生日期
      from 读者
      where 读者姓名='李明'
)

一些带有existsnot exists谓词的子查询不能被其他形式的子查询等价替换,但所有带in谓词、比较运算符、anyall谓词的子查询都能用带exists谓词的子查询等价替换。

带有exists量词的相关子查询只关心内层查询是否有返回值,尽管内层查询要执行多次,但其效率并不一定低于不相关查询。