MYSQL中使用子查询进行过滤

子查询

查询(query) 任何SQL语句都是查询。但此术语一般指SELECT语句。

SQL还允许创建子查询(subquery),即嵌套在其他查询中的查询

利用子查询进行过滤

例子:假如需要列出订购物品RGAN01的所有客户
(1) 检索包含物品RGAN01的所有订单的编号。
(2) 检索具有前一步骤列出的订单编号的所有客户的ID。
(3) 检索前一步骤返回的所有客户ID的客户信息。

输入

SELECT order_num 
FROM OrderItems 
WHERE prod_id = 'RGAN01';

输出

+-----------+
| order_num |
+-----------+
|     20007 |
|     20008 |
+-----------+

输入

SELECT cust_id 
FROM Orders 
WHERE order_num IN (20007,20008); 

输出

+------------+
| cust_id    |
+------------+
| 1000000004 |
| 1000000005 |
+------------+

输入

SELECT cust_id
FROM orders
WHERE order_num IN (SELECT order_num
                    FROM orderitems
                    WHERE prod_id = 'RGAN01');

输出

+------------+
| cust_id    |
+------------+
| 1000000004 |
| 1000000005 |
+------------+

分析:在SELECT语句中,子查询总是从内向外处理。在处理上面的SELECT语句时,MySQL实际上执行了两个操作
首先是:
SELECT order_num FROM orderitems WHERE prod_id = ‘RGAN01’
次查询返回连个订单号:20007和20008。然后这两个值以IN操作符要求的逗号分隔的格式传递给外部查询的WHERE子句。

外部查询完成:
SELECT cust_id FROM orders WHERE order_num IN(20007,20008)
可以看到,输出是正确的并与前面硬编码WHERE子句所返回的值相同。

现在得到了订购物品RGAN01的所有客户的ID。下一步是检索这些客户ID的客户信息。

输入

SELECT cust_name,cust_contact
FROM customers
WHERE cust_id IN ('1000000004','1000000005');

可以把其中的WHERE子句转换为子查询而不是硬编码这些客户ID:

输入

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 = 'RGAN01'));

输出

+---------------+--------------------+
| cust_name     | cust_contact       |
+---------------+--------------------+
| Fun4All       | Denise L. Stephens |
| The Toy Store | Kim Howard         |
+---------------+--------------------+

分析:
为了执行上述SELECT语句,MySQL实际上必须执行3条SELECT语句。最里边的子查询返回订单号列表,此列表用于其外面的子查询的WHERE子句。外面的子查询返回客户ID列表,此客户ID列表用于最外层查询的WHERE子句。最外层查询确实返回所需的数据。

作为计算字段使用子查询

使用子查询的另一方法是创建计算字段。假如需要显示customers表中每个客户的订单总数。订单与相应的客户ID存储在orders表中。

为了执行这个操作,遵循下面的步骤。
(1) 从customers表中检索客户列表。
(2) 对于检索出的每个客户,统计其在orders表中的订单数目。

使用SELECT COUNT(*)对表中的行进行计数,并且通过提供一条WHERE子句来过滤某个特定的客户ID,可仅对该客户的订单进行计数。
为了对每个客户执行COUNT(*)计算,应该将COUNT(*)作为一个子查询

输入

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 |
+---------------+------------+--------+
| Fun4All       | IN         |      1 |
| Fun4All       | AZ         |      1 |
| Kids Place    | OH         |      0 |
| The Toy Store | IL         |      1 |
| Village Toys  | MI         |      2 |
+---------------+------------+--------+

分析:这条SELECT语句对customers表中每个客户返回3列:cust_name、cust_state和orders。orders是一个计算字段,它是由圆括号中的子查询建立的。该子查询对检索出的每个客户执行一次。在此例子中,该子查询执行了5次,因为检索出了5个客户。

子查询中的WHERE子句与前面使用的WHERE子句稍有不同,因为它使
用了完全限定列名(在第4章中首次提到)。下面的语句告诉SQL比较
orders表中的cust_id与当前正从customers表中检索的cust_id:

WHERE orders.cust_id = customers.cust_id

相关子查询(correlated subquery) 涉及外部查询的子查询
这种类型的子查询称为相关子查询。
任何时候只要列名可能有多义性,就必须使用这种语法(表名和列名由一个句点分隔)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章