SELECT语句是SQL的查询。迄今为止我们所看到的所有SELECT语句都是简单查询,即从单个数据库表中检索数据的单条语句。
SQL还允许创建子查询(subquery),即嵌套在其他查询中的查询。为什么要这样做呢?理解这个概念的最好方法是考察几个例子。
注意了,如果某个表的查询需要用到其他表的查询的结果的时候,就要用子查询了。
比如,我们想查出订购了TNT2的所有用户,怎么办?
第一步,我们找出来TNT2的订单编号。
下一步,查询具有订单20005和20007的客户ID.
SELECT cust_id FROM orders WHERE order_num IN(20005,20007);
是不是感觉特别low? low就对了。
第二个查询要用到第一个查询的结果,所以我们可以把第一个查询变成一个子查询。
SELECT cust_id FROM orders WHERE order_num IN (SELECT order_num FROM orderitems WHERE prod_id='TNT2');
在SELECT语句中,子查询总是从内向外处理。在处理上面的SELECT语句时,MySQL实际上执行了两个操作:
首先,它执行下面的查询:
SELECT order_num FROM orderitems WHERE prod_id='TNT2'
此查询返回两个订单号:20005和20007。然后,这两个值以IN操作符要求的逗号分隔的格式传递给外部查询的WHERE子句.
因此外查询变成了:
SELECT cust_id FROM orders WHERE order_num IN(20005,20007);
包含子查询的SELECT语句难以阅读和调试。所以要注意缩进。
别忘了,我们只是拿到了用户的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='TNT2'));
最外层查询确实返回所需的数据。
注意!!!
列必须匹配 在WHERE子句中使用子查询(如这里所示),应该保证SELECT语句具有与WHERE子句中相同数目的列。通常,子查询将返回单个列并且与单个列匹配,但如果需要也可以使用多个列。
也就是说,外层SELECT中查的列数,与WHERE中的列数应该是相同的。
虽然子查询一般与IN操作符结合使用,但也可以用于测试等于(=
)、不等于(<>
)等。
子查询效率一般。最好用Join
。
使用子查询的另一方法是创建计算字段。假如需要显示customers
表中每个客户的订单总数。订单与相应的客户ID存储在orders
表中。
为了执行这个操作,遵循下面的步骤。
customers的表结构是这样的:
而orders表是这样的:
我们开始:
可使用SELECT COUNT(*)
对表中的行进行计数,并且通过提供一条WHERE子句来过滤某个特定的客户ID,可仅对该客户的订单进行计数。例如,下面的代码对客户10001的订单进行计数:
SELECT COUNT(*) AS orders FROM orders WHERE cust_id=10001;
我们要对每一个cust_id都进行计数,咋整?意思是对于每个cust_id都做一次运算。
这个应该是写在select里的。只有这样才能做到这一点。
为了对每个客户执行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;
该子查询对检索出的每个客户执行一次。在此例子中,该子查询执行了5次,因为检索出了5个客户。
下面的语句告诉SQL比较orders表中的cust_id与当前正从customers表中检索的cust_id:
WHERE orders.cust_id=customers.cust_id
相关子查询
即,涉及外部查询的子查询。任何时候只要列名可能有多义性,就必须使用这种语法(表名和列名由一个句点分隔)。不然会造成混乱。
写子查询时,要先写内层,再写外层,一步一步来。不要着急。