目录
1、子查询
SELECT 语句是 SQL 的查询。我们迄今为止所看到的所有 SELECT 语句都是简单查询,即从单个数据库表中检索数据的单条语句。
查询(query) :任何 SQL 语句都是查询。但此术语一般指 SELECT 语句。
SQL 还允许创建子查询(subquery),即嵌套在其他查询中的查询。为什么要这样做呢?理解这个概念的最好方法是考察几个例子。
说明:MySQL 支持
如果使用 MySQL,应该知道对子查询的支持是从 4.1 版本引入的。MySQL 的早期版本不支持子查询。
2、利用子查询进行过滤
现在,假如需要列出订购物品 ANV01 的所有顾客的信息,应该怎样检索?下面列出具体的步骤。
- 找到包含物品 ANV01 的订单号
- 根据订单号找到顾客的ID
- 根据顾客的ID查找顾客的信息
-- 先找到有订购 ANV01 的订单号
SELECT order_num
FROM orderitems
WHERE prod_id = 'ANV01';
-- 20005
-- 在找到该订单号的所有顾客id
SELECT cust_id
FROM orders
WHERE order_num IN (20005);
-- 10001
-- 最后根据顾客id返回顾客的信息
SELECT cust_name, cust_contact
FROM customers
WHERE cust_id IN (10001);
这里使用子查询是如何呢?就是在过滤时以子查询的结果作为过滤的条件:
-- 使用子查询
SELECT cust_name, cust_contact
FROM customers
WHERE cust_id IN (SELECT cust_id
FROM orders
WHERE order_num IN (SELECT order_num
FROM orderitems
WHERE prod_id = 'ANV01');
为了执行上述 SELECT 语句,DBMS 实际上必须执行三条 SELECT 语句。最里边的子查询返回订单号列表,此列表用于其外面的子查询的 WHERE子句。外面的子查询返回顾客 ID 列表,此顾客 ID 列表用于最外层查询的 WHERE 子句。最外层查询返回所需的数据。
可见,在 WHERE 子句中使用子查询能够编写出功能很强且很灵活的 SQL语句。对于能嵌套的子查询的数目没有限制,不过在实际使用时由于性能的限制,不能嵌套太多的子查询。
注意:只能是单列:作为子查询的 SELECT 语句只能查询单个列。企图检索多个列将返回错误。
3、作为计算字段使用子查询
使用子查询的另一方法是创建计算字段。假如需要显示 Customers 表中每个顾客的订单总数。订单与相应的顾客 ID 存储在 Orders 表中。执行这个操作,要遵循下面的步骤:
- 从 Customers 表中检索顾客列表;
- 对于检索出的每个顾客,统计其在 Orders 表中的订单数目。
这里有一个问题,就是要对所有顾客进行订单统计,也就是包括并没有订单的顾客。
- 使用上面子查询用于过滤的效果:没有订单的顾客不会进行统计
SELECT COUNT(*) AS cust_oders
FROM orders
WHERE cust_id IN (SELECT cust_id
FROM customers)
GROUP BY cust_id;
-- 上面会有一种问题,就是没有订单的顾客不会显示订单数,显然不符合需求
-- 我们需要对customers中的每一个cust_id进行统计,所以不能用IN
- 作为计算字段使用子查询:
-- 所以cust_id不应该以订单表为准,应该以顾客表为准,但是又需要与订单表中的id进行比较
-- 这里开始使用完全限定列名:即表名+列名,作为计算字段使用子查询:
SELECT cust_name,
cust_id,
(SELECT COUNT(*)
FROM orders
WHERE Orders.cust_id = Customers.cust_id) AS cust_orders
FROM customers
ORDER BY cust_name;
/*
上面sql语句较为复杂:它首先从customers中拿到了整个表的数据
然后逐行检索出cust_name,cust_id
其中的计算字段是一个select子查询,因为已经拿到了所有Customers.cust_id
所以可以逐行以其为过滤条件,去统计该id再orders中的行数,如果没有就为0行
*/
这条 SELECT 语句对 Customers 表中每个顾客返回三列:cust_name、cust_state 和 orders。orders 是一个计算字段,它是由圆括号中的子查询建立的。该子查询对检索出的每个顾客执行一次。(也就是说,过滤后的数据是一行一行进行计算的)
子查询中的 WHERE 子句与前面使用的 WHERE 子句稍有不同,因为它使用了完全限定列名,而不只是列名( cust_id)。它指定表名和列名(Orders.cust_id 和 Customers.cust_id)。下面的 WHERE 子句告诉 SQL,比较Orders表中的cust_id和当前正从Customers表中检索的cust_id:WHERE Orders.cust_id = Customers.cust_id
4、小结
- 子查询就是在SELECT语句中嵌套了SELECT语句,但是这种子查询只能查询单列,否则会报错
- 除了用于过滤外,子查询还可用于计算字段,过滤后的结果是一行一行进行计算的
- 当两表或多表中有相同的属性列,需要使用完全限定名--即表名.列名,避免混淆