【第4章】复杂查询

本章介绍第 2 章 2.2.3 节“复杂查询”相关的知识和面试题。考查知识点:

y 子查询、临时表 with...as、视图、case 表达式(用于多条件判断)。

4.1子查询

工作中的业务问题有时比较复杂,就需要用子查询来进行复杂查询了。那什么是子查询呢?

子查询就是在from 子句中直接写SQL查询语句,也就是将多个SQL 查询语句嵌套在一起。这个嵌套的 SQL 查询语句就是子查询。

使用子查询时,可以把子查询看作临时表,也就是子查询的查询结果表,因为这个查询结果表并不是真实存放在数据库中的表,所以把这样的表称为临时表。

使用子查询时,一般需要用 as 关键字给子查询起个别名,方便在 SQL 其他地方使用。另外,如果不用 as 关键字给子查询起别名,那么有时候会报错:“1248 - Every derived table must have its own alias”。

通过下面的面试题,我们来学习如何用子查询解决问题。

面试题8:查找成绩排名第二的学生成绩

【题目】

表 4.1 所示“成绩表”记录了学生选修课程的名称及成绩。现在需要找出语文课中成绩排名第二的学生成绩。如果不存在第二名成绩的学生,那么查询应返回 null。

【解题思路】

可以把问题拆解为以下两步。

(1)找出所有选修了语文课的学生的成绩。SQL 语句的书写方法如下:

(2)在语文课的成绩中,找出排名第二的学生成绩。

①考虑到成绩可能有一样的值,所以使用关键字 distinct 对成绩进行去重,SQL 语句的书写方法如下:

②把第①步的查询结果(最高的成绩)记为 a(给子查询用 as 关键字起个别名叫作 a,方便在 SQL 的其他地方使用),然后找出小于 a 的所有成绩,SQL 语句的书写方法如下:

③在小于 a 的所有成绩中,最大值就是课程成绩排在第二名的值。

把上述 SQL 语句合并在一起就是最终答案。需要注意,在条件语句中编写子查询时,不能包含别名。这是因为该子查询会被当作单个值而不是一个表,最终 SQL 语句如下所示:

查询结果如表 4.2 所示。

【本题考点】

(1)汇总函数(最大值 max())的用法。

(2)去掉重复数据关键字 distinct 的用法。

(3)子查询的用法,子查询经常被当作中间结果的临时表来使用。

嵌套的 SQL 查询语句用括号括起来,叫作子查询。为了方便使用子查询,一般会用 as 关键字给子查询起个别名。

子查询还可以结合逻辑运算符 in、any、all,从而构建复杂的查询。

4.1.1 in(子查询)

in 常用于 where 子句中,表示查询某个范围内的数据。in 和子查询结合在一起的用法是: in(子查询)。

通过下面的面试题,我们来学习如何应用 in(子查询)解决实际问题。

面试题9:如何找出多条件的用户

【题目】

表 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 语句组合在一起,最终如下:

4.1.2 all(子查询)和 any(子查询)

all(子查询)和 any(子查询)需要和比较运算符,包括“大于(>)”“小于(<)”“不等于 (<>)”等一起使用。

1. all( 子查询 )

all 常用于 where 子句中,表示要满足 all(子查询)里的所有条件。下面通过两个表格:表格 A 和表格 B,来直观地展示如何使用 all(子查询),如图 4.1 所示。

第一种情况,>all( 子查询 )。下面的 SQL 语句表示,表格B 中大于 all( 子查询) 中子查询结果的所有数据,如图 4.2 所示。

第二种情况,<all( 子查询 )。下面的 SQL 语句表示,表格 B 中小于 all( 子查询 ) 中子查询结果的所有数据,如图 4.3 所示。

第三种情况,<>all( 子查询 )。下面的 SQL 语句表示,表格 B 中不等于 all( 子查询 ) 中子查询结果的所有数据。所以,<>all( 子查询 ) 的作用等同于 not in ( 子查询 ),如图 4.4 所示。

等同于:

2. any(子查询)

any 常用于 where 子句中,表示只需满足 ang( 子查询 ) 里的任意一个条件就可以。通过刚才的表格 A 和表格 B 来演示,如图 4.5 所示。

第一种情况,>any( 子查询 )。下面的 SQL 语句表示,表格 B 中大于 any( 子查询 ) 中子查询结果的任意一个数字的数字,等同于表格 B 中大于表格 A 中的最小值(2)的数字, 如图 4.6 所示。

第二种情况,表格 B 中的数字等于 any( 子查询 )(等同于:in( 子查询 ))中子查询结果的任意一个数字,即父查询的结果集满足存在于子查询的结果集中这个条件,如图 4.7 所示。

等同于:

第三种情况,表格 B 中的数字小于 any( 子查询 ) 中子查询结果中的任意一个数字,即父查询的结果集满足小于子查询的任意一个值这个条件,则为真。此处案例要求得到的值小于子查询结果集中的最大值,如图 4.8 所示。

4.2临时表with…as

在实际工作中,有时候业务问题很复杂,这时的 SQL 语句中会嵌套太多子查询,那么SQL 语句的可读性就会变差,有没有好的办法解决这样的问题呢?

答案是用 with...as 语句。

with…as 语句可以将 SQL 语句中的子查询定义为临时表,起到提高 SQL 语句可读性的作用,因此它也被归为子查询部分。

with...as 语句定义临时表的语法如下:

可以看到,一个 with...as 语句中可以定义多个临时表,多个临时表用“,”分隔(注意: with...as 语句定义临时表结束后,不能加语句结束符“;”)。

使用临时表时,可以用 select 语句查询临时表中的数据。例如,4.1.1 节面试题 9 的 SQL 语句如下:

里面有3个子查询,分别是:

我们用 with...as 语句将这 3 个子查询分别定义为临时表 a、b、c。SQL 语句的书写方法如下:

使用 with...as 语句需要注意如下几点。

(1)用 with...as 语句定义的临时表,后面必须直接跟使用该临时表的 SQL 语句,否则临时表将失效,如图 4.9 所示。

(2)用 with...as 语句定义的临时表不需要删除,因为它在创建并使用后即释放,不会真实存放在数据库里。可以理解为,将一条 SQL 语句中的一部分片段封装起来,方便使用。因此, 用 with...as 语

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

SQL面试宝典 文章被收录于专栏

本书以SQL的基础知识为出发点,从SQL的简单查询、汇总函数、分组,到多表查询、窗口函数等SQL高级功能,逐一进行介绍与讲解,基本涵盖了学习SQL过程中需要掌握的主要内容。 本书结合大量的面试题,让读者清楚地了解如何用所学的SQL知识解决工作中的实际问题。提供了从不同行业、不同岗位的业务场景出发的实战项目训练,便于读者在实践中学习,巩固知识和技能,理解与掌握相关内容,并将其快速应用于实际工作中。

全部评论
点赞 回复
分享
发布于 03-07 20:44 广东
点赞 回复
分享
发布于 03-07 20:53 黑龙江
滴滴
校招火热招聘中
官网直投
点赞 回复
分享
发布于 03-07 20:58 山东
点赞 回复
分享
发布于 03-07 21:05 上海
点赞 回复
分享
发布于 03-07 21:15 江苏
点赞 回复
分享
发布于 03-07 21:21 广东
点赞 回复
分享
发布于 03-07 21:27 上海
点赞 回复
分享
发布于 03-07 21:33 上海

相关推荐

头像
不愿透露姓名的神秘牛友
04-08 00:50
点赞 评论 收藏
转发
9 1 评论
分享
牛客网
牛客企业服务