博客
关于我
第十章:SQL Server2019数据库之多行子查询
阅读量:114 次
发布时间:2019-02-26

本文共 5573 字,大约阅读时间需要 18 分钟。

目录

学前必备知识

多行子查询通过多行比较操作符来实现,其返回值为多行。常用的多行比较操作符包括:IN 和 NOT IN、ALL 和 ANY/SOME、EXISTS 和 NOT EXISTS 操作符,本文主要介绍这几种多行比较操作符的应用。

一、使用 IN、NOT IN 操作符的多行子查询

IN 子查询是指在外层查询和子查询之间用 IN 进行连接,判断某个属性列是否在子查询的结果中,其返回的结果中可以包含零个或者多个值。在 IN 子句中,子查询和输入多个运算符的数据的区别在于,使用多个运算符输入时,一般都会输入两个或者两个以上的数值,而使用子查询时,不能确定其返回结果的数量。但是,即使子查询返回的结果为空,语句也能正常运行。

由于在子查询中,查询的结果往往是一个集合,所以 IN 子查询是子查询中最常用的。IN 子查询语句的操作步骤可以分成两步:

  1. 执行内部子查询。
  2. 根据子查询的结果再执行外层查询。IN 子查询返回列表中的每个值,并显示任何相等的数据行。

【示例01】获取 tb_book 图书表和 tb_book_author 作者表中具有相同部门 (tb_author_department) 的作者所写的图书信息。SQL 语句如下:

SELECT * FROM tb_bookWHERE book_sort IN(SELECT tb_author_department FROM tb_book_author WHERE tb_book.book_sort=tb_book_author.tb_author_department)ORDER BY tb_book.book_price;

查询结果如下图所示:

在这里插入图片描述
子查询还可以用在外层查询的 NOT IN 子句中,以产生 NOT IN 使用的清单。如果外层查询中用来比较的数据被查询出与子查询产生的结果集中的所有值都不匹配,那么 NOT IN 子句返回 TRUE,然后将该记录指定列的值输入到最终的结果集中。

【示例02】查询在 tb_book 图书表中列出,而在 tb_book_author 作者表中没有列出的作者所在部门的图书信息。SQL 语句如下:

SELECT * FROM tb_bookWHERE book_sort NOT IN(SELECT tb_author_department FROM tb_book_author);

查询结果如下图所示:

在这里插入图片描述
小结:tb_book_author 作者表中的作者部门有 PHP 和 VC,通过与 tb_book图书表的对比,发现 ASP 和 SQL 数据库这两个部门在 tb_book 图书表中列出,而在 tb_book_author 作者表中没有列出。使用 NOT IN 子查询的查询速度很慢,在对 SQL 语句的性能有所要求的时候,就要使用性能更好的语句来替代 NOT IN。例如,可以使用外连接的方式替换 NOT IN 以提高语句的执行速度。一般来说,使用 NOT IN 和子查询的语句结构更容易理解和编写,所以只在对 SQL 语句的性能有要求时,才使用外连接来替换 NOT IN 和子查询联用的结果。

【练习1】在 course 和 grade 表中,查询没有学生参加考试的课程信息。

【练习2】在 student 表中,查询 课程成绩 大于 98 分的学生信息。

二、 EXISTS 子查询与 NOT EXISTS 子查询

EXISTS 子查询的功能是判断子查询的返回结果中是否有数据行。如果子查询返回的结果是空集,则判断为不存在,即 EXISTS 失败,NOT EXISTS 成功。如果子查询返回至少一行的数据记录,则判断存在,即 EXISTS 成功,NOT EXISTS 失败。由于 EXISTS 子查询中不需要返回具体值,所以该子查询的选择列表常用 SELECT *格式,其外层的 WHERE 子句中也不需要指定列名。

EXISTS 通常都和相关子查询一起使用。在使用相关子查询时,对外表中的每一行,子查询都要运行一遍,该行的值也要在子查询的 WHERE 子句中被使用。这样,通过 EXISTS 子句就能将外层表中的各行数据依次与子查询处理的内层表中的数据进行存在性比较,得到需要的结果。关键字 EXISTS 引入子查询的语法特点如下:

  1. 关键字 EXISTS 一般直接跟在外层查询的 WHERE 子句后面。它的前面没有列名、常量或者表达式。
  2. 关键字 EXISTS 引入的子查询的 SELECT 列表清单可以而且通常都是由 * 组成的。因为只是测试满足子查询的数据行的存在性,所以在子查询的 SELECT 列表清单中加入列名没有实际意义。

1、比较使用 EXISTS 和 IN 的查询

EXISTS 子查询和 IN 操作符可以实现同一个功能,但是两者之间是有区别的。第 1 个查询使用 EXISTS,而第 2 个查询使用 IN。注意两个查询返回相同的信息。

(1) 使用谓词 EXISTS 的 SQL 语句如下:

SELECT DISTINCT goods_nameFROM goodsWHERE EXISTS(	SELECT * FROM brand 	WHERE cat_id = goods.cat_id AND name='索尼/SONY');

(2) 使用谓词 IN 的 SQL 语句如下:

SELECT DISTINCT goods_nameFROM goodsWHERE cat_id IN(	SELECT cat_id FROM brand 	WHERE cat_id = goods.cat_id AND name='索尼/SONY');

这两种方法返回相同的查询结果,如下图所示:

在这里插入图片描述
2、比较使用 EXISTS 和 ”=ANY“ 的查询

通过 orderform 订单表与 user_address 用户地址表,查找两个表中相同国家的收货人姓名。通过两种查询方法:

(1) 使用 EXISTS 的 SQL 语句如下:

SELECT consignee,country FROM orderformWHERE EXISTS(SELECT country FROM user_address WHERE orderform.country=user_address.country);

(2) 使用 “=ANY” 的 SQL 语句如下:

SELECT consignee,country FROM orderformWHERE country = ANY(SELECT country FROM user_address);

这两种方法返回相同的查询结果。

【示例03】获取 tb_book 图书表和 tb_book_author 作者表中,具有相同部门的作者所写的图书信息。SQL 语句如下:

SELECT * FROM tb_bookWHERE EXISTS(SELECT * FROM tb_book_author WHERE tb_book.book_sort=tb_book_author.tb_author_department)ORDER BY tb_book.book_price;

查询结果如下图所示:

在这里插入图片描述
一些带 EXISTS 或者 NOT EXISTS 的子查询不能被其他形式的子查询等价交换,但所有带 IN、ANY、ALL 和比较运算符的子查询都能用带 EXISTS 的子查询等价替换。

3、NOT EXISTS 子查询实现两个表的差集

与 EXISTS 相对应的是 NOT EXISTS。使用 NOT EXISTS 后,如果子查询的结果为空,则外层的 WHERE 子句返回 TRUE。

【示例04】获取 tb_book 图书表与 tb_book_author 作者表中相同部门以外的图书信息。SQL 语句如下:

SELECT * FROM tb_bookWHERE NOT EXISTS(SELECT tb_author_department FROM tb_book_author WHERE tb_book.book_sort=tb_book_author.tb_author_department)ORDER BY tb_book.book_price;

【练习3】查询没参加考试的学生信息。

【练习4】查询报名人数大于平均报名人数的课程信息。
【练习5】查询学生选课表(StuCou) 中报名状态为 "报名"的课程名。
【练习6】查询已经报名选修课程的学生信息,要求显示学号和姓名。

三、 通过量词实现多行子查询

1、使用量词实现多行查询

ALL、SOME 和 ANY 是量词,允许将比较运算符左边的单值与生成单列但多行结果集的子查询(在比较运算符的右边)相比较。如果 WHERE 子句中的子查询生成多个值的单列结果,将终止以下形式的查询:

SELECT 
FROM
{ =|<>|>|>=|<|<=}
WHERE

下面通过几个例子来了解如何使用量词实现多行子查询。

(1) 在 goods 商品信息表中查询同类商品中,售价高于平均售价的商品信息。SQL 语句如下:

SELECT cat_id,goods_name,shop_priceFROM goodsWHERE shop_price < (	SELECT AVG(shop_price) FROM goods GROUP BY cat_id);

执行 SQL 语句,如下图所示:

在这里插入图片描述
如果通过使用 3 个量词(ALL、SOME、ANY或其他) 之一引入子查询,而将查询语句改写如下:

SELECT 
FROM
{ =|<>|>|>=|<|<=} { SOME|ANY|ALL}
WHERE

如果子查询的单列结果表有不止一行的数据,此时将不会终止查询。而是将 <expression>(比较运算符左边) 的值与比较运算符右边的子查询返回的每个值进行比较。

(2) 改写上面的 SQL 语句,加入量词 SOME,再次执行查询语句,就不会出现错误信息。SQL 语句如下:

SELECT cat_id,goods_name,shop_priceFROM goodsWHERE shop_price < SOME(	SELECT AVG(shop_price) FROM goods GROUP BY cat_id);

查询结果如下图所示:

在这里插入图片描述
如果使用 ALL 量词,<expression> 值与 <subquery> 每一个值的比较都必须求值为 TRUE,才能使 WHERE 子句求值为 TRUE;另一方面,只要至少 <expression> 与 <subquery> 返回值之一的比较求值为 TRUE,SOME 和 ANY 量词就使 WHERE 子句求值为 TRUE。

2、使用 ALL 操作符的多行子查询

ALL 操作符比较子查询返回列表中的每一个值。<ALL 为小于最小的;>ALL 为大于最大的;而 =ALL 则没有返回值,因为在等于子查询的情况下,返回列表中的所有值是不符合逻辑的。

ALL 允许将比较运算符前面的单值与比较运算符后面的子查询返回值的集合中的每一个值相比较。另外,仅当所有(ALL)的比较运算符左边的单值与子查询返回值的集合中的每一个值的比较都求值为 TRUE 时,比较判式(以及 WHERE子句)才求值为 TRUE。

【示例05】获取所有商品售价低于本身品牌的平均售价的商品信息。SQL 语句如下:

SELECT cat_id,goods_name,shop_priceFROM goodsWHERE shop_price < ALL(	SELECT AVG(shop_price) FROM goods GROUP BY cat_id);

查询结果如下:

在这里插入图片描述

3、使用 ANY/SOME 操作符的多行子查询

ANY 操作符比较子查询返回列表中的每一个值。<ANY 为小于最大的;>ANY 为大于最小的;而 =ANY 为等于 IN。ANY 允许将比较运算符前面的单值与比较运算符后面的子查询返回值的集合中的每一个值相比较。另外,仅当所有(ANY) 的比较运算符左边的单值与子查询返回值的集合中的一个值的比较求值为 TRUE 时,比较判式(以及WHERE子句)的求值就为 TRUE。

【示例06】获取商品的售价比平均售价高的商品信息,并按商品品牌进行划分。SQL 语句如下:

SELECT cat_id,goods_name,shop_priceFROM goodsWHERE shop_price > ANY(	SELECT AVG(shop_price) FROM goods GROUP BY cat_id);

查询结果如下图所示:

在这里插入图片描述
量词 SOME 和 ANY 是同义的,它们都允许将比较运算符前面的单值与比较运算符后面的子查询返回的结果集中的每个值进行比较。如果比较运算符前面的单值与比较运算符后面的子查询返回的结果集中的每个值之间的任何 (ANY) 比较求值为 TRUE,那么判式(以及 WHERE 子句)求值为 TRUE。

总结:本章主要介绍了多行子查询。多行子查询通过多行比较操作符来实现,比较常用的多行比较操作符包括:IN 和 NOT IN、ALL 和 ANY/SOME、 EXISTS 和 NOT EXISTS 操作符。

转载地址:http://qcik.baihongyu.com/

你可能感兴趣的文章
MQTT 保留消息
查看>>
MQTT 持久会话与 Clean Session 详解
查看>>
MQTT介绍及与其他协议的比较
查看>>
MQTT工作笔记0007---剩余长度
查看>>
MQTT工作笔记0008---服务质量
查看>>
MQTT工作笔记0009---订阅主题和订阅确认
查看>>
Mqtt搭建代理服务器进行通信-浅析
查看>>
MS COCO数据集介绍
查看>>
MS Edge浏览器“STATUS_INVALID_IMAGE_HASH“兼容性问题
查看>>
ms sql server 2008 sp2更新异常
查看>>
MS SQL查询库、表、列数据结构信息汇总
查看>>
MS UC 2013-0-Prepare Tool
查看>>
MSBuild 教程(2)
查看>>
msbuild发布web应用程序
查看>>
MSB与LSB
查看>>
MSCRM调用外部JS文件
查看>>
MSCRM调用外部JS文件
查看>>
MSEdgeDriver (Chromium) 不适用于版本 >= 79.0.313 (Canary)
查看>>
MsEdgeTTS开源项目使用教程
查看>>
msf
查看>>