14.1 利用子查询进行过滤
现在,假如需要列出订购物品TNT2的所有客户,应该怎样检索?下面列出具体的步骤。
- 检索包含物品TNT2的所有订单的编号。
- 检索具有前一步骤列出的订单编号的所有客户的ID。
- 检索前一步骤返回的所有客户ID的客户信息。
上述每个步骤都可以单独作为一个查询来执行。可以把一条SELECT语句返回的结果用于另一条SELECT语句的WHERE子句。
mysql> 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='TNT2'));
+----------------+--------------+
| cust_name | cust_contact |
+----------------+--------------+
| Coyote Inc. | Y Lee |
| Yosemite Place | Y Sam |
+----------------+--------------+
- 分析:最里边的子查询返回订单号列表,此列表用于其外面的子查询的WHERE子句。外面的子查询返回客户ID列表,此客户ID列表用于最外层查询的WHERE子句。最外层查询确实返回所需的数据。
对于能嵌套的子查询的数目没有限制,不过在实际使用时由于性能的限制,不能嵌套太多的子查询。虽然子查询一般与IN操作符结合使用,但也可以于测试等于(=)、不等于(<>)等。
列必须匹配:在WHERE子句中使用子查询(如这里所示),应该保证SELECT语句具有与WHERE子句中相同数目的列。
14.2 作为计算字段使用子查询
mysql> SELECT cust_name, cust_state,(
-> SELECT COUNT(*) FROM orders WHERE orders.cust_id = customers.cust_id) AS orders FROM customers ORDER BY cust_name;
+----------------+------------+--------+
| cust_name | cust_state | orders |
+----------------+------------+--------+
| Coyote Inc. | MI | 2 |
| E Fudd | IL | 1 |
| Mouse House | OH | 0 |
| Wascals | IN | 1 |
| Yosemite Place | AZ | 1 |
+----------------+------------+--------+
- 分析:这 条 SELECT 语 句 对
customers
表 中 每 个 客 户 返 回 3 列 :cust_name
、cust_state
和orders
。orders
是一个计算字段,它是由圆括号中的子查询建立的。该子查询对检索出的每个客户执行一次。在此例子中,该子查询执行了5次,因为检索出了5个客户。
子查询中的WHERE
子句与前面使用的WHERE
子句稍有不同,因为它使用了完全限定列名。下面的语句告诉SQL比较orders
表中的cust_id
与当前正从customers
表中检索的cust_id
:
WHERE orders.cust_id = customers.cust_id
相关子查询(correlated subquery) 涉及外部查询的子查询。
这种类型的子查询称为相关子查询。任何时候只要列名可能有多义性,就必须使用这种语法(表名和列名由一个句点分隔)。