子查询的特点概括起来就是一张一次性视图,是将用来定义视图的SELECT语句直接用于FROM子句当中。
原则上子查询必须设定名称,为子查询设定名称时需要使用AS关键字,该关键字有时也可以省略
一、单层子查询
实际上,该SELECT语句包含嵌套的结构,首先会执行FROM子句中的SELECT语句,然后才会执行外层的SELECT语句,即
-
首先执行FROM子句中的SELECT语句(子查询)
SELECT product_type, COUNT(*) AS cnt_product
FROM Product
GROUP BY product_type;
-
根据
1
的结果执行外层的SELECT语句
SELECT product_type, cnt_product FROM ProductSum;
二、多层子查询
由于子查询的层数原则上没有限制,因此可以像“子查询的FROM子句中还可以继续使用子查询,该子查询的FROM子句中还可以再使用子查询……”这样无限嵌套下去
SELECT product_type, cnt_product
FROM (SELECT *
FROM (SELECT product_type, COUNT(*) AS cnt_product
FROM Product
GROUP BY product_type) AS ProductSum
WHERE cnt_product = 4) AS ProductSum2;
注:随着子查询嵌套层数的增加,SQL语句会变得越来越难读懂,性能也会越来越差。因此,请大家尽量避免使用多层嵌套的子查询。
三、标量子查询
标量就是单一的意思,标量子查询有一个特殊的限制,那就是必须而且只能返回1行1 列的结果,也就是返回表中某一行的某一列的值,例如“10”或者“北京”这样的值。
由于返回的是单一的值,因此标量子查询的返回值可以用在=或者<>这样需要单一值的比较运算符之中。这也正是标量子查询的优势所在。
-- 实例 计算平均销售单价的标量子查询
SELECT AVG(sale_price) FROM Product;
1.在WHERE子句中使用标量子查询
WHERE 子句中不能使用聚合函数,可以使用标量子查询代替聚合函数
SELECT product_id, product_name, sale_price
FROM Product
WHERE sale_price> (SELECT AVG(sale_price) FROM Product);
2.标量子查询的书写位置
标量子查询的书写位置并不仅仅局限于WHERE子句中,通常任何可以使用单一值的位置都可以使用。也就是说,能够使用常数或者列名的地方,无论SELECT子句、GROUPBY子句、HAVING子句,还是ORDER BY子句,几乎所有的地方都可以使用。
例如,在SELECT子句当中使用之前计算平均值的标量子查询的SQL语句
SELECT product_id,product_name,sale_price,
(SELECT AVG(sale_price) FROM Product) AS avg_price
FROM Product;
注意:标量子查询绝对不能返回多行结果。
也就是说,如果子查询返回了多行结果,那么它就不再是标量子查询,而仅仅是一个普通的子查询了,因此不能被用在 = 或 者 <> 等需要单一输入值的运算符当中,也不能用在 SELECT 等子句当中。
三、关联子查询
使用子查询只能选取出销售单价(sale_price)高于全部商品平均销售单价的商品。这次我们稍稍改变一下条件,选取出各商品种类中高于该商品种类的平均销售单价的商品。
-- 按照商品种类计算平均价格
SELECT AVG(sale_price)
FROM Product
GROUP BY product_type;
但是,如果我们使用标量子查询的方法,直接把上述SELECT 语句使用到 WHERE 子句当中的话,就会发生错误。
-- 发生错误的子查询
SELECT product_id, product_name, sale_price
FROM Product
WHERE sale_price > (SELECT AVG(sale_price)
FROM Product
GROUP BY product_type);
出错的原因是:该子查询会返回多行结果,并不是标量子查询。在 WHERE 子句中使用子查询时,该子查询的结果必须是单一的,即标量子查询。
但是如果想要获得分组后每个分组大于平均值(或其他函数值)的数据,比如说:数学成绩大于数学平均分的数据,语文成绩大于语文平均分的数据…,这时候就需要使用关联子查询。
SELECT product_type, product_name, sale_price
FROM Product AS P1
WHERE sale_price > (SELECT AVG(sale_price)
FROM Product AS P2
WHERE P1.product_type = P2.product_type --关键
GROUP BY product_type);
这里起到关键作用的就是在子查询中添加的 WHERE 子句的条件。该条件的意思就是,在同一商品种类中对各商品的销售单价和平均单价进行比较。
总结:
-
在细分的组内进行比较时,需要使用关联子查询
-
结合条件一定要写在子查询中,具体来讲,子查询内部设定的关联名称,只能在该子查询内部使用,换句话说,就是“内部可以看到外部,而外部看不到内部”