工作中的业务问题有时比较复杂,就需要用子查询来进行复杂查询了。那什么是子查询呢?
子查询就是在from子句中直接写SQL查询语句,也就是将多个SQL查询语句嵌套在一起。这个嵌套的SQL查询语句就是子查询。
使用子查询时,可以把子查询看作临时表,也就是子查询的查询结果表,因为这个查询结果表并不是真实存放在数据库中的表,所以把这样的表称为临时表。
使用子查询时,一般需要用as关键字给子查询起个别名,方便在SQL其他地方使用。另外,如果不用as关键字给子查询起别名,那么有时候会报错:“1248-Every derived table must have its own alias”。
通过下面的面试题,我们来学习如何用子查询解决问题。
表4.1所示“成绩表”记录了学生选修课程的名称及成绩。现在需要找出语文课中成绩排名第二的学生成绩。如果不存在第二名成绩的学生,那么查询应返回null。
表4.1 成绩表
可以把问题拆解为以下两步。
(1)找出所有选修了语文课的学生的成绩。
SQL语句的书写方法如下:
(2)在语文课的成绩中,找出排名第二的学生成绩。
①考虑到成绩可能有一样的值,所以使用关键字distinct对成绩进行去重,SQL语句的书写方法如下:
②把第①步的查询结果(最高的成绩)记为a(给子查询用as关键字起个别名叫作a,方便在SQL的其他地方使用),然后找出小于a的所有成绩,SQL语句的书写方法如下:
③在小于a的所有成绩中,最大值就是课程成绩排在第二名的值。
把上述SQL语句合并在一起就是最终答案。需要注意,在条件语句中编写子查询时,不能包含别名。这是因为该子查询会被当作单个值而不是一个表,最终SQL语句如下所示:
查询结果如表4.2所示。
表4.2 语文课中成绩排名第二的学生成绩
(1)汇总函数(最大值max())的用法。
(2)去掉重复数据关键字distinct的用法。
(3)子查询的用法,子查询经常被当作中间结果的临时表来使用。
嵌套的SQL查询语句用括号括起来,叫作子查询。为了方便使用子查询,一般会用as关键字给子查询起个别名。
子查询还可以结合逻辑运算符in、any、all,从而构建复杂的查询。
in常用于where子句中,表示查询某个范围内的数据。in和子查询结合在一起的用法是:in(子查询)。
通过下面的面试题,我们来学习如何应用in(子查询)解决实际问题。
表4.3所示的“销售订单表”记录了销售情况,每一条数据表示哪位顾客、哪一天、在哪个交易网点购买了什么产品,购买的数量是多少,以及对应产品的零售价。
表4.3 销售订单表
现在请查找既购买过ProductA产品又购买过ProductB产品,但没有购买ProductC产品的顾客人数。
需要把满足以下3个条件的顾客查找出来。
(1)购买过ProductA产品的顾客。
(2)购买过ProductB产品的顾客。
(3)没有购买ProductC产品的顾客。
具体步骤如下。
(1)购买过ProductA产品的顾客,可以用in(子查询),SQL语句的书写方法如下:
(2)购买过ProductB产品的顾客,可以用in(子查询),SQL语句的书写方法如下:
(3)没有购买ProductC产品的顾客,可以在in前面加not,表示不在in里面的数据,也就是not in(子查询),SQL语句的书写方法如下:
计算满足条件的顾客人数,把上面3步的SQL语句组合在一起,最终如下:
all(子查询)和any(子查询)需要和比较运算符,包括“大于(>)”“小于(<)”“不等于(<>)”等一起使用。
1.all(子查询)
all常用于where子句中,表示要满足all(子查询)里的所有条件。下面通过两个表格:表格A和表格B,来直观地展示如何使用all(子查询),如图4.1所示。
图4.1 all(子查询)案例演示
第一种情况,>all(子查询)。下面的SQL语句表示,表格B中大于all(子查询)中子查询结果的所有数据,如图4.2所示。
第二种情况,<all(子查询)。下面的SQL语句表示,表格B中小于all(子查询)中子查询结果的所有数据,如图4.3所示。
图4.2 查询表格B中大于表格A的最大值的数字
图4.3 查询表格B中小于表格A的最小值的数字
第三种情况,<>all(子查询)。下面的SQL语句表示,表格B中不等于all(子查询)中子查询结果的所有数据。所以,<>all(子查询)的作用等同于not in(子查询),如图4.4所示。
等同于:
图4.4 查询表格B中不等于表格A中数字的数字
2.any(子查询)
any常用于where子句中,表示只需满足ang(子查询)里的任意一个条件就可以。通过刚才的表格A和表格B来演示,如图4.5所示。
第一种情况,>any(子查询)。下面的SQL语句表示,表格B中大于any(子查询)中子查询结果的任意一个数字的数字,等同于表格B中大于表格A中的最小值(2)的数字,如图4.6所示。
图4.5 any(子查询)案例演示
图4.6 查询表格B中大于表格A的最小值的数字
第二种情况,表格B中的数字等于any(子查询)(等同于:in(子查询))中子查询结果的任意一个数字,即父查询的结果集满足存在于子查询的结果集中这个条件,如图4.7所示。
图4.7 查询表格B中等于表格A的值的数字
等同于:
第三种情况,表格B中的数字小于any(子查询)中子查询结果中的任意一个数字,即父查询的结果集满足小于子查询的任意一个值这个条件,则为真。此处案例要求得到的值小于子查询结果集中的最大值,如图4.8所示。
图4.8 查询表格B中小于表格A的最大值