10.3.6 使用子查询
子查询是一个嵌套在另一个查询内部的查询。虽然大多数子查询功能可以通过连接和临时表的使用而获得,但是子查询通常更容易阅读和编写。
1.基本的子查询
子查询的最常见用法是用一个查询的结果作为另一个查询的比较条件。例如,如果希望找到一个金额最大的订单,可以使用如下所示的查询:
select customerid,amount
from orders
where amount=(select max(amount)from orders);
该查询将给出如下所示的结果:
+——————+————+
|customerid|amount|
+——————+————+
|2|74.98|
+——————+————+
在这个例子中,子查询返回了单一值(最大金额),然后再用作输出查询的比较条件。这是使用子查询的好例子,因为这个特定查询无法使用ANSI SQL的连接来完成。
但是,这个关联查询将产生相同的输出:
select customerid,amount
from orders
order by amount desc
limit 1;
由于它依赖LIMIT,这个查询与大多数RDBMS并不兼容,但是在MySQL中,它的执行比子查询版本的查询效率更高。
MySQL很长时间没有采纳子查询的主要原因之一在于,多数查询可以在没有子查询的情况下完成。从技术角度看,可以创建具有相同作用的单一合法的ANSI SQL查询,但是这将依赖低效率的MAX-CONCAT。
就像本例一样,可以在所有常见比较操作符中使用子查询值。还有一些可供使用的特殊子查询比较操作符,这将在下一节详细介绍。
2.子查询和操作符
特殊的子查询操作符共有5个。其中有4个可以在常规子查询中使用,而另一个(EXISTS)通常只在相关联的子查询中使用,相关联的子查询将在下一节介绍。表10-4列出了常见的4个子查询操作符。
这些操作符都只可以出现在比较操作符之后,除了IN,它相当于隐藏了比较操作符(=)。
3.关联子查询
在关联子查询中,情况变得更加复杂。在关联子查询中,可以在内部查询中使用外部查询的结果。例如:
select isbn,title
from books
where not exists
(select*from order_items where order_items.isbn=books.isbn);
这个查询说明了关联子查询和最后一个特殊子查询操作符(EXISTS)的使用。它将检索任何还没有被订购的图书(这与使用左关联所检索到的信息相同)。请注意,内部查询只能包括FROM列表中的order_items表,但是还是引用了books.isbn。换句话说,内部查询将引用外部查询的数据。这是关联子查询的定义:查询匹配(或者,在这个例子中,是不匹配)外部行的内部行。
如果子查询中存在任何匹配行,EXISTS操作符将返回true。相反,如果子查询中没有任何匹配行,NOT EXISTS将返回true。
4.行子查询
目前介绍的所有子查询都将返回单一的值,虽然在大多数情况下,该值为true或false(就像前面使用EXISTS的例子)。行子查询将返回整行,它可以与外部查询的整行进行比较。通常,这种方法用来在一个表中查找存在于另一个表的行。在图书数据库中,并没有一个很好的例子。但是,该语法的常规例子可以如下所示:
select c1,c2,c3
from t1
where(c1,c2,c3)in(select c1,c2,c3 from t2);
5.使用子查询作为临时表
可以在一个外部查询的FROM子句中使用子查询。这种方法允许有效地查询子查询的输出,并将其当作一个临时表。
作为最简单的例子,临时表的使用如下所示:
select*from
(select customerid,name from customers where city='Box Hill')
as box_hill_customers;
请注意,我们将子查询放在了FROM子句中。在子查询后面就是结束的括号,必须为子查询的结果定义一个别名。我们可以将其当作外部查询的任何表。