开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 24 天,点击查看活动详情
子查询
MySQL 4.1 引入了对子查询的支持
前面我们记录过的 select 语句都是从单个数据库表中检索数据的单条语句。SQL 还允许嵌套在其他查询中的查询,即子查询(subquery)。
利用子查询进行过滤
如果一条
select语句的返回结果可以被用于另一条select语句的where子句中,那么我们可以将这两条查询语句组合成一条语句,这就利用到了子查询。
我们知道,在MySQL中使用的数据库表都是关系表。
假设,现在有三张表:
orders表:存储订单号,客户ID,订单日期orderitems表:存储各订单的物品customers表:存储实际的客户信息
然后,需求是列出订购物品 abc 的所有客户,此时应该怎样检索?步骤如下:
-
检索包含物品
abc的所有订单的编号;输入:
select order_id from orderitems where prod_id = 'abc';输出:
+----------+ | order_id | +----------+ | 10001 | | 10007 | +----------+ -
检索步骤一列出的订单编号的所有客户ID;
输入:
select cust_id from orders where order_id in (10001, 10007);输出:
+---------+ | cust_id | +---------+ | 2005 | | 2009 | +---------+ -
最后是返回步骤二检索出的客户ID的客户信息。
输入:
select cust_name, cust_contact from customers where cust_id in (2005, 2009);
现在,我们可以将步骤一和步骤二变为子查询,即组合两个查询,记录如下:
select
cust_id
from
orders
where
order_id in (
select
order_id
from
orderitems
where
prod_id = 'abc';
);
此时的输出结果为:
+---------+
| cust_id |
+---------+
| 2005 |
| 2009 |
+---------+
记录:
-
在
select语句中,子查询总是从内向外进行处理。 -
在上述子查询的例子中,MySQL 实际上会先执行下面的查询:
select order_id from orderitems where prod_id = 'abc';该查询返回了两个订单号:
10001和10007。然后,这两个值以IN操作符要求的逗号分隔的格式传递给外部查询的where子句。此时的外部查询变为:select cust_id from orders where order_id in (10001, 10007);
当然,我们也可以利用子查询将三条语句组合成一条。可见,在 where 子句中利用子查询能够编写出灵活强大的 SQL 语句。
注意,由于性能的限制,不宜过多嵌套子查询。
作为计算字段使用子查询
使用子查询的另一个方法就是创建计算字段。
假设,我们现在有两张表:
customers表:包含客户信息以及订单信息orders表:包含订单以及相应的客户ID
现在我们需要返回每个客户的订单总数,步骤如下:
- 从
customers表中检索出客户ID列表 - 根据客户ID,统计其在
orders表中的订单数目
在之前,我们对某个客户(比如 1001)的订单进行计数,可以是这样:
select
count(*) as orders
from
orders
where
cust_id = 1001;
现在,我们需要返回每个客户的订单总数,此时应该将 count(*) 作为一个子查询。
如下所示:
select
cust_name,
(
select count(*)
from orders
where orders.cust_id = customers.cust_id
) as orders
from
customers
order by
cust_name;
记录:
orders是一个计算字段,它由圆括号中的子查询建立的。- 该子查询对检索出的每个客户执行一次。
备注:
where order.cust_id = customers.cust_id- 上述语句使用了完全限定列名,其用于告诉 SQL 比较
orders表中的cust_id与当前正在从customers表中检索的cust_id