《SQL必知必会》--子查询

第十一课 使用子查询

在前十课中,我们所有的操作、指令都是在一张表列中执行,现在,欢迎进入多表联动的世界!

什么是子查询

SELECT语句是SQL的查询。
我们之前看到的所有的SELECT语句都是简单查询,即从单个数据库表中检索数据的单条语句。
SQL还允许创建子查询。

子查询(subquery)即嵌套在其他查询中的查询。

如何利用子查询进行过滤

目前,我将SQL语句分为主语句和条件语句。主语句就是select...from...,而在其之后的就属于条件语句。

利用子查询进行过滤就是在过滤数据时,即条件语句处使用子查询。例如:

1
2
3
4
5
select cust_name, cust_address
from customers
where cust_id IN (select cust_id
from orders
where order_date >= '2020-02-01' );

这条指令的含义是检索2020-02-01之后下订单的客户姓名和客户地址。

  • 作为子查询的SELECT语句只能查询单列;
  • MySQL系统中子查询不能使用LIMIT指令。

作为计算字段使用子查询

与上类似,作为计算字段使用子查询,即在主语句中使用子查询语句。例如:

先看一个检索顾客1000000001订单次数总数的代码:

1
2
3
SELECT COUNT(*) AS order
from Orders
WHERE cust_id = '1000000001';

如果不仅仅对顾客1000000001执行count(*),而且还要检索每一个顾客对应的总订单次数,需要使用子查询。请看下面代码:

1
2
3
4
5
6
7
select cust_name,
cust_state,
(select count(*)
from orders
where orders.cust_id = Customers.cust_id) as orders
from customers
order by cust_name;

Tips:在有可能混淆列名的情况下,必须使用完全限定列名。
完全限定列名:表名.列名(customers.cust_id)

在这里必须使用完全限定列名的原因就在与,如果不这样做,那么DBMS系统将默认cust_id = cust_id是处于同一张表列内,那么这就是绝对成立的了,于是返回的数字固定等于该列总行数。

可能还是有同学看不懂这条代码,我们深入解读以下。

首先,去除子查询语句,单单看这一个简单的查询语句。

1
2
3
4
select cust_name,
cust_state
from customers
order by cust_name;

这简单的查询语句返回的结果就是按照cust_name排序的cust_name,cust_state两列。

1
2
3
4
5
6
7
cust_name    cust_state
--------- ----------
Fun4All IN
Fun4All AZ
Kids Place OH
The Toy Store IL
Village Toys MI

然后,我们再看子查询语句。

1
2
3
   (select count(*) 
from orders
where orders.cust_id = Customers.cust_id) as orders

这句简单的子查询语句本质上是双循环语句。
内循环是order表列,外循环为customers表列。
按照cust_name排序,第一行的customers.cust_id=(cust_name=Fun4All时对应的id,假设100000001),此时上述的代码就变换为:

1
2
3
   (select count(*) 
from orders
where orders.cust_id = 1000000001) as orders

经过上述代码的运行,第一行记录就出来了,然后继续按照cust_name排序循环,直到遍历数据库表customers

1
2
3
4
5
6
7
cust_name    cust_state    orders
--------- ---------- ------
Fun4All IN 1
Fun4All AZ 1
Kids Place OH 0
The Toy Store IL 1
Village Toys MI 2

小结

跨表操作中的子查询的两种形式:作为过滤条件的子查询和作为计算字段的子查询。