示例中涉及的表、数据参考链接进行创建:
https://www.jianshu.com/p/480d20bf2370
子查询简介:
子查询即嵌套在其他查询中的查询(任何sql都是查询,但此处仅指select)
利用子查询进行过滤:
已知:订单存储在两个表中,对于包含订单号、客户ID、订单日期的每个订单,orders表存储一行,各订单物品存储在相关的orderitems表中,orders表不存储客户信息,他只存储客户的ID,实际的客户信息存储在customers表中。
现在假如需要列出订购物品TNT2的所有客户,应该怎样检索?步骤如下:
(1) 检索包含物品TNT2的所有订单编号
(2) 检索具有前一步骤列出的订单编号的所有客户的ID
(3) 检索前一步骤返回的所有客户ID的客户信息
上述每个步骤都可以单独作为一个查询来执行,可以吧一条select语句返回的结果用于另一条select语句的where子句
也可以使用子查询把3个查询语句组合成一条语句
第一条select语句的含义很明确,对于prod_id为TNT2的所有订单物品,他检索order_num列,输出列出两个包含此物品的订单:
下一步,查询具有订单20005和20007的客户ID。利用前面介绍的IN子句,编写如下select语句
现在把第一个查询变成子查询组合两个查询,如下所示
在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);
可以看到,输出是正确的并且与前面硬编码where子句所返回的值相同。
现在已经得到了订购物品TNT2的所有客户的ID,下一步是检索这些客户ID对应的客户信息,检索两列的SQL语句如下
select cust_name, cust_contact from customers where cust_id in (10001,10004);
可以把其中的where子句转换为子查询而不是硬编码这些客户ID,如下所示
为了执行上述select语句,MySQL实际上必须执行3条select语句,最里边的子查询返回订单号列表,此列表用于其外面的子查询的where子句,外面的子查询返回客户ID列表,此客户ID列表用于最外层查询的where子句,最外层查询确实返回所需的数据。
注意事项:
(1) MySQL对于对于能嵌套的子查询的数目没有限制,但考虑到性能的因素,在实际使用的过程中不建议嵌套太多的子查询
(2) 在where子句中使用子查询,应该保证select语句具有与where子句中相同数目的列,通常子查询将返回单个列并且与单个列匹配,但如果需要也可以匹配多个列
作为计算字段使用子查询:
使用子查询的另一个方法是创建计算字段,加入需要显示customers表中每个客户的订单总数,订单与相应的客户ID存储在orders表中。
为了实现这个需求,可用以下步骤:
(1) 从customers表中检索客户列表
(2) 对于检索的每个客户,统计其在orders表中的订单数目
正如之前所说,可使用 select count(*) 对表中的行数进行计数,并且通过提供一条where子句来过滤某个特定的客户ID,可仅对该客户的订单进行计数,如下代码就是对客户10001的订单进行计数:
select count(*) as orders from orders where cust_id=10001;
为了对每个客户执行count(*)计算,应该将count(*) 作为一个子查询,如下代码所示:
这条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
如上所示,涉及外部(不同表)的子查询又叫做相关子查询,任何时候只要列名可能有多义性,就必须使用这种语法(表明和列名由一个句点分隔),加入不这样处理,则会发生如下状况:
显然返回的结果不正确,那么为什么会这样呢?有两个cust_id列,一个在orders中,另一个在customers中,需要比较两个列以正确的把订单与它相应的顾客匹配,如果不是完全限定的列名,MySQL将假定你是对orders表中的cust_id进行自身比较,而select count(*) from orders where cust_id=cust_id总是返回orders表中的订单总数。
**********书山有路,学海无涯,无数个孤独的夜晚,需要一点小小的成就感!**********