第7章 子查询

第7章 子查询

子查询是一个嵌套在SELECT、INSERT、UPDATE或DELETE语句,或者其他子查询中的查询,任何允许使用表达式的地方都可以使用子查询。子查询和表的连接一样,提供了使用单个查询访问多个表中数据的方法。本章将主要介绍子查询的基本结构及其应用。

7.1 子查询简单应用

子查询在SQL语句中应用的非常的广泛。本节中将讲解有关子查询的一些基础知识和一些简单的应用。

7.1.1 子查询概述

子查询被广泛应用在数据管理和维护当中。子查询可以嵌套在SQL语句中使用,子查询的结果将作为外层查询的参数,这与函数调用的嵌套很相似,即将一个函数调用作为另一个函数的输入参数。子查询在SQL语句中的作用非常大,在通常的情况下,外层查询语句执行一行,子查询语句将执行一遍,然后判断外层查询语句的条件是否满足。如果条件满足,则外层查询语句得到的数据行就是结果集中的行;如果条件不满足,则外层查询语句继续执行下一行数据。

子查询具有以下几个方面的特点:

  • 子查询的SQL语句非常最接近于查询的英文描述。
  • 有些SQL查询语句必须使用子查询才能够表达出来。
  • 子查询可以将查询分解为多个部分,然后再将这些部分拼接起来,从而能够编写出更加简单的SELECT语句。

在使用子查询执行操作时,应该注意以下几点:

  • 作为子查询的SELECT语句可以包含FROM子句、WHERE子句、HAVING子句和GROUP BY子句,其中WHERE子句不可以被省略,其他子句可以被省略。
  • 在SQL语句中,子查询必须使用括号括起来,以便于判断子查询语句的开始和结束。
  • 由关键字IN引入的内层子查询的SELECT列表中只允许有一个列名或表达式。而且在子查询的SELECT列表中命名的列必须能与在外围语句的WHERE子句中命名的列连接兼容。
  • 如果一个数据表只包含在子查询中,而没有出现在外层查询中,则外层查询选择列表中不能包含该数据表的列。
  • 在使用关键字EXISTS引入的子查询的SELECT列表中不需要指定具体的列名,可以都由星号“*”组成。
  • 在子查询中不允许使用ORDER BY子句。
  • 子查询允许嵌套多层,并且最多可以嵌套255层。

子查询可以嵌套在另一个SELECT语句的FROM子句、WHERE子句或者是HAVING子句中,它还可以嵌套在INSERT语句、UPDATE语句和DELETE语句中,甚至子查询的外围查询也可以是一个子查询,即嵌套子查询。

7.1.2 在多表中使用子查询
子查询通常应用在多个数据表当中,用于实现数据处理和维护。
【上机实战】
通过子查询查询员工考勤数据表(T_KQ)中员工编号为“1003”的考勤信息,并且在员工信息表(T_EMPLOY)中存在该员工的基本信息。为了便于读者进行分析比较,现将员工信息表(T_EMPLOY)和员工考勤数据表(T_KQ)中现有的数据信息显示出来。
显示员工信息表(T_EMPLOY)中的数据信息。

SELECT * FROM T_EMPLOY

显示员工考勤数据表(T_KQ)中的数据信息。

SELECT * FROM T_KQ

上述代码执行以后,分别如图7.1所示和7.2所示。
在这里插入图片描述
图7.1 员工信息表(T_EMPLOY)中的数据信息
在这里插入图片描述
图7.2 员工考勤表(T_KQ)中的数据信息
使用子查询查询员工考勤信息的代码如下所示。

SELECT
E_ID,E_CD_NUMS,E_ZT_NUMS,E_SJ_NUMS,E_KG_NUMS,E_YF
FROM T_KQ
WHERE E_ID=(SELECT E_ID FROM T_EMPLOY WHERE E_ID =1003)

代码执行以后,其执行结果如图7.3所示。
在这里插入图片描述
图7.3 通过子查询查询数据信息
通过子查询还可以从多个数据表中获取数据信息,如下面的示例所示。
通过子查询从员工信息表(T_EMPLOY)中获取员工姓名和部门信息,从员工考勤数据表(T_KQ)中获取员工的考勤信息,该信息在员工信息表(T_EMPLOY)中存在并且员工姓名为“王丽”,其实现的代码如下所示。

SELECT 
A.E_ID,A.E_NAME,A.E_BM,B.E_CD_NUMS,B.E_ZT_NUMS,B.E_SJ_NUMS,B.E_KG_NUMS,B.E_YF
FROM T_EMPLOY A,T_KQ B
WHERE A.E_ID=B.E_ID AND 
A.E_NAME=(SELECT E_NAME FROM T_EMPLOY WHERE E_NAME = '王丽')

代码执行以后,其执行结果如图7.4所示。
在这里插入图片描述
图7.4 通过子查询从多个数据表中获取数据信息
从图中可以看出,上述代码中括号内的SELECT语句即为子查询语句,该语句作为WHERE子句后面的一个条件查询语句,将符合条件的数据信息查询出来。
再看下面的代码,使用子查询将除员工姓名为“王丽”的员工考勤信息全部显示出来,其实现的代码如下所示。

SELECT 
A.E_ID,A.E_NAME,A.E_BM,B.E_CD_NUMS,B.E_ZT_NUMS,B.E_SJ_NUMS,B.E_KG_NUMS,B.E_YF
FROM T_EMPLOY A,T_KQ B
WHERE A.E_ID=B.E_ID AND 
A.E_NAME !=(SELECT E_NAME FROM T_EMPLOY WHERE E_NAME = '王丽')

代码执行以后,其执行结果如图7.5所示。
在这里插入图片描述
图7.5 在子查询中使用“!=”运算符
7.1.3 在子查询中使用聚合函数
聚合函数除了可以用在SELECT语句中之外,还可以应用在子查询当中。
【上机实战】
在员工信息表(T_EMPLOY)中,查询员工基本工资高于所有员工平均工资的员工工资信息,其实现的代码如下所示。

SELECT * FROM T_EMPLOY
WHERE E_GZ>(SELECT AVG(E_GZ) FROM T_EMPLOY)

代码执行以后,其执行结果如图7.6所示。
在这里插入图片描述
图7.6 在子查询中使用AVG函数
从上述代码中可以看出,子查询首先计算出所有员工的平均工资,然后再以此为条件查询员工工资大于员工平均工资的员工工资信息。可以看出,如果子查询返回的是单一的值,就可以使用任何一种比较运算符比较列值。

注意:通过比较运算符不仅可以比较数字,还可以比较字符串。

子查询还可以使用在WHERE子句的表达式中。
下面的代码演示的是,在员工信息表(T_EMPLOY)中查询员工的工资信息,并且要求每个部门员工的平均工资都高于1200元,其实现的代码如下所示。

SELECT * from T_EMPLOY T
WHERE (SELECT AVG(E_GZ) FROM T_EMPLOY WHERE E_BM=T.E_BM)>1200

代码执行以后,其执行结果如图7.7所示。
在这里插入图片描述
图7.7 在WHERE子句的表达式中使用子查询
在WHERE子句中,比较判断表达式的任意一边都可以使用聚合函数子查询。
下面的代码演示的是,在员工信息表(T_EMPLOY)中查询员工的工资信息,并且要求每个部门的平均工资都高于所有部门的平均工资,其实现的代码如下所示。

SELECT * from T_EMPLOY T
WHERE (SELECT AVG(E_GZ) FROM T_EMPLOY WHERE E_BM=T.E_BM)>
(SELECT AVG(E_GZ) FROM T_EMPLOY)

代码执行以后,其执行结果如图7.8所示。
在这里插入图片描述
图7.8 在表达式的两边都使用聚合函数子函数
子查询还可以用在SELECT语句的查询列当中。
下面的代码演示的是,在员工信息表(T_EMPLOY)中查询所有员工的编号、姓名以及在员工扣款(T_KQ)数据表中具有这个员工的扣款记录条数信息,其实现的代码如下所示。

SELECT E_ID,E_NAME,
(SELECT COUNT(*) FROM T_KQ WHERE E_ID=T_EMPLOY.E_ID)
FROM T_EMPLOY

代码执行以后,其执行结果如图7.9所示。
在这里插入图片描述
图7.9 在SELECT语句的查询列中使用子函数
7.1.4 使用ANY或ALL运算符
ANY和ALL关键字用于修改引入子查询的比较运算符。ANY运算符表示与子查询中的每一个值进行比较,在比较过程中如果有一个比较值为真,则整个子查询结果集的比较值就为真。在使用ALL运算符进行批量比较时,该运算符会将一个表达式的值与子查询返回的一列值中的每个数据进行比较,只有所有的比较结果都为真,整个子查询结果集的比较才为真。表7.1是比较运算符与ALL或ANY连用时的取值情况。
表7.1 比较运算符与ALL或ANY连用时的取值情况
比较运算符 修饰符 所取子查询结果中的值

在这里插入图片描述

下面通过示例来说明如何使用ALL或ANY运算符。
【上机实战】
从员工信息表(T_EMPLOY)中查询其他部门中比采购部所有员工工资都高的员工信息,其实现的代码如下所示。员工信息表(T_EMPLOY)中的数据信息请参照图7.1。

SELECT *
FROM T_EMPLOY
WHERE E_GZ>ALL(SELECT E_GZ FROM T_EMPLOY WHERE E_BM='采购部')
AND E_BM<>'采购部'

代码执行以后,其执行结果如图7.10所示。
在这里插入图片描述
图7.10 ALL函数的使用
下面讲解一下ANY子查询的应用示例。
下面的代码演示的是,从员工信息表(T_EMPLOY)中查询除了工资最低的员工以外所有的员工信息,其实现的代码如下所示。员工信息表(T_EMPLOY)中的数据信息请参照图7.1。

SELECT *
FROM T_EMPLOY
WHERE E_GZ>ANY(SELECT E_GZ FROM T_EMPLOY)

代码执行以后,其执行结果如图7.11所示。
在这里插入图片描述
图7.11 ANY函数的应用示例

7.2 使用子查询维护数据
除了查询数据之外,使用子查询可以向数据表中插入数据,也可以修改或删除数据表中的数据信息。本节中将讲解一下使用子查询维护数据的实现方法。

7.2.1 子查询在INSERT语句中的使用
使用子查询可以向数据表中插入数据,如下面的示例所示。
【上机实战】
在员工信息表(T_EMPLOY)中,查询该数据表中每个部门的平均工资都高于所有部门平均工资的员工信息,并且将这些数据插入到T_EMPLOY1数据表当中,其实现的代码如下所示。

INSERT INTO T_EMPLOY1(E_ID,E_NAME,E_BM,E_GZ)
SELECT E_ID,E_NAME,E_BM,E_GZ
FROM T_EMPLOY T
WHERE (SELECT AVG(E_GZ) FROM T_EMPLOY WHERE E_BM=T.E_BM)>
(SELECT AVG(E_GZ) FROM T_EMPLOY)

代码执行以后,通过下面的语句查询T_EMPLOY1数据表中的数据信息。

SELECT * FROM T_EMPLOY1

代码执行以后,其执行结果如图7.12所示。
在这里插入图片描述
图7.12 通过子查询插入数据表中的数据信息
从执行的结果可以看出,通过子查询将T_EMPLOY数据表中符合条件的数据信息插入到了T_EMPLOY1数据表当中。
再看下面的示例。
在员工信息表(T_EMPLOY)中查询所有员工的编号、姓名以及在员工扣款(T_KQ)数据表中具有这个员工的扣款记录条数信息,并且将这些数据信息插入到T_EMPLOY1数据表当中,其实现的代码如下所示。

INSERT INTO T_EMPLOY1(E_ID,E_NAME,E_NUMS)
SELECT E_ID,E_NAME,
(SELECT COUNT(*) FROM T_KQ WHERE E_ID=T_EMPLOY.E_ID)
FROM T_EMPLOY

代码执行以后,通过下面的语句查询T_EMPLOY1数据表中的数据信息。

SELECT * FROM T_EMPLOY1

代码执行以后,其执行结果如图7.13所示。

说明:在查询数据之前,为了查看本示例的效果,需要使用DELETE语句清空T_EMPLOY数据表中的数据信息。

在这里插入图片描述
图7.13 通过子查询插入数据表中的数据信息
7.2.2 子查询在UPDATE语句中的使用
通过子查询还可以修改数据表中的数据信息,如下面的示例所示。
【上机实战】
在员工信息表(T_EMPLOY)中,查询员工基本工资高于所有员工平均工资的员工工资信息,并且将这些员工的工资都在原来的基础上再增加100元。
为了便于比较,首先将T_EMPLOY数据表中的数据信息显示出来。

SELECT * FROM T_EMPLOY

代码执行以后,其执行结果如图7.14所示。
在这里插入图片描述
图7.14 T_EMPLOY数据表中的数据信息
通过子查询修改T_EMPLOY数据表中数据信息的实现代码如下所示。

UPDATE T_EMPLOY T SET E_GZ=E_GZ+100
WHERE E_GZ>(SELECT AVG(E_GZ) FROM T_EMPLOY)

代码执行以后,通过下面的语句查询T_EMPLOY1数据表中的数据信息。

SELECT * FROM T_EMPLOY

代码执行以后,其执行结果如图7.15所示。
在这里插入图片描述
图7.15 通过子查询修改数据表中的数据信息
7.2.3 子查询在DELETE语句中的使用
除了添加和修改数据信息之外,还可以使用子查询删除数据表中的数据信息。
【上机实战】
在员工信息表(T_EMPLOY)中,查询员工基本工资高于所有员工平均工资的员工工资信息,并且将这些数据信息删除,其实现的代码如下所示。

DELETE T_EMPLOY
WHERE E_GZ>(SELECT AVG(E_GZ) FROM T_EMPLOY)

代码执行以后,通过下面的语句查询T_EMPLOY数据表中的数据信息。

SELECT * FROM T_EMPLOY

代码执行以后,其执行结果如图7.16所示。
在这里插入图片描述
图7.16 通过子查询删除数据表中的数据信息
7.3 使用IN语句的子查询
IN子查询是通过IN(或NOT IN)运算符连接起来的一种查询数据的方法,即把源表中的列值与子查询返回的结果进行比较,如果列值与返回结果集中的列数据值之一相匹配,则IN的判别式求值为True,并且查询结果中包含这些数据。
7.3.1 简单的IN语句子查询
本节中我们讲解一下简单的IN语句子查询。
【语法说明】
IN语句子查询的语句格式如下所示。

SELECT column_name
FROM table_name
WHERE expression [NOT] IN(subquery)

语句中的expression可以是实际值、列名、表达式或者是子查询。
【上机实战】
在员工信息表(T_EMPLOY)中,通过子查询查询员工基本工资高于1000的员工工资信息,其实现的代码如下所示。

SELECT * FROM T_EMPLOY
WHERE E_GZ IN (SELECT E_GZ FROM T_EMPLOY WHERE E_GZ >1000)

代码执行以后,其执行结果如图7.17所示。
在这里插入图片描述
图7.17 简单的IN语句子查询应用
7.3.2 使用IN子查询实现集合交运算
使用IN子查询可以实现集合的交运算。
【上机实战】
在员工信息表(T_EMPLOY)中,通过子查询查询员工基本工资高于1000的员工工资信息,同时这些员工都属于“信息部”的员工,其实现的代码如下所示。

SELECT * FROM T_EMPLOY
WHERE E_BM ='信息部' 
AND E_GZ IN (SELECT E_GZ FROM T_EMPLOY WHERE E_GZ >1000)

代码执行以后,其执行结果如图7.18所示。
在这里插入图片描述
图7.18 使用IN子查询实现集合交运算

说明:可以将上述代码看作是在员工信息表(T_EMPLOY)中,查询部门为“信息部”的员工信息与查询员工工资大于1000的员工信息的交集。

7.3.3 使用IN子查询实现集合差运算
使用IN子查询可以实现集合的差运算。
【上机实战】
在员工信息表(T_EMPLOY)中,查询所有符合员工部门为“信息部”,并且员工姓名不是“赵刚”的员工信息。

SELECT * FROM T_EMPLOY
WHERE E_BM ='信息部' 
AND E_NAME NOT IN (SELECT E_NAME FROM T_EMPLOY WHERE E_NAME='赵刚')

代码执行以后,其执行结果如图7.19所示。
在这里插入图片描述
图7.19 使用IN子查询实现集合差运算

说明:可以将上述代码看作是在员工信息表(T_EMPLOY)中,查询部门为“信息部”的员工信息与查询员工姓名是“赵刚”员工信息的差集。

7.4 使用EXISTS语句的子查询
在使用EXISTS语句的子查询中,如果子查询返回的结果是空集,则判断为不存在,即EXISTS判式的值为False。如果子查询返回至少一行的数据记录,则判断为存在,即EXISTS判式的值为True。
7.4.1 简单的EXISTS语句子查询
使用EXISTS引入的子查询与其他子查询在以下两个方面有所不同。

  • EXISTS关键字前面没有列名、常量或其他表达式。
  • 由EXISTS引入的子查询的选择列表通常都由星号(*)组成。

【语法说明】
EXISTS子查询的语法格式如下所示:

SELECT column_name
FROM table_name
WHERE [NOT] EXISTS (subquery)

上述代码中,只要子查询subquery中返回的结果表中存在记录,则WHERE子句的结果就为True。如果要使EXISTS判式有意义,就应该在子查询中建立搜索条件以匹配子查询连接起来的两个表中的值。
【上机实战】
在员工信息表(T_EMPLOY)中查询员工的数据信息,并且只查询那些在员工考勤数据表(T_KQ)中存在员工编号的数据信息。为了便于读者进行分析比较,现将员工信息表(T_EMPLOY)和员工考勤数据表(T_KQ)中现有的数据信息显示出来。
显示员工信息表(T_EMPLOY)中的数据信息。

SELECT * FROM T_EMPLOY

显示员工考勤数据表(T_KQ)中的数据信息。

SELECT * FROM T_KQ

上述代码执行以后,分别如图7.20所示和7.21所示。
在这里插入图片描述
图7.20 员工信息表(T_EMPLOY)中的数据信息
在这里插入图片描述
图7.21 员工考勤表(T_KQ)中的数据信息
使用EXISTS语句查询T_EMPLOY数据表中数据信息的代码如下所示。

SELECT *
FROM  T_EMPLOY T
WHERE EXISTS(SELECT * FROM T_KQ WHERE E_ID=T.E_ID)
ORDER BY E_ID

代码执行以后,其执行结果如图7.22所示。
在这里插入图片描述
图7.22 EXISTS语句子查询应用
7.4.2 使用EXISTS子查询实现两表交集
前面介绍了使用IN子查询可以实现两个表的交集运算,使用EXISTS子查询同样也可以实现两个表之间的交集运算。下面通过一个示例来具体地讲解。
【上机实战】
在员工信息表(T_EMPLOY)中查询员工的数据信息,并且只查询那些在员工考勤数据表(T_KQ)中存在员工编号的数据信息,同时这些员工都属于“采购部”的员工,其实现的代码如下所示。
员工信息表(T_EMPLOY)与员工考勤数据表(T_KQ)中的数据信息,请参考图7.20与图7.21。

SELECT *
FROM  T_EMPLOY T
WHERE E_BM ='采购部' AND 
EXISTS(SELECT * FROM T_KQ WHERE E_ID=T.E_ID)
ORDER BY E_ID

代码执行以后,其执行结果如图7.23所示。
在这里插入图片描述
图7.23 使用EXISTS子查询实现两表交集
7.4.3 使用EXISTS子查询实现两表并集
上一节中介绍了使用EXISTS子查询实现的交集运算。然而,使用EXISTS子查询也可以实现两个表之间的并集运算。请看下面的示例讲解。
【上机实战】
在员工信息表(T_EMPLOY)中查询员工的数据信息,并且只查询那些在员工考勤数据表(T_KQ)中存在员工编号的数据信息,或者部门属于“采购部”的员工信息,其实现的代码如下所示。
员工信息表(T_EMPLOY)与员工考勤数据表(T_KQ)中的数据信息,请参考图7.19与图7.20。

SELECT *
FROM  T_EMPLOY T
WHERE E_BM ='采购部' OR
EXISTS(SELECT * FROM T_KQ WHERE E_ID=T.E_ID)
ORDER BY E_ID

代码执行以后,其执行结果如图7.24所示。
在这里插入图片描述
图7.24 使用EXISTS子查询实现两表并集
7.4.4使用NOT EXISTS的子查询
NOT EXISTS可以用在查询空集的操作上,其表示SQL语句中,如果子查询不成功,则NOT EXISTS查询成功。
【上机实战】
在员工信息表(T_EMPLOY)中查询员工的数据信息,并且只查询那些在员工考勤数据表(T_KQ)中不存在员工编号的数据信息,其实现的代码如下所示。
员工信息表(T_EMPLOY)与员工考勤数据表(T_KQ)中的数据信息,请参考图7.20与图7.21。

SELECT *
FROM  T_EMPLOY T
WHERE
NOT EXISTS(SELECT * FROM T_KQ WHERE E_ID=T.E_ID)
ORDER BY E_ID

代码执行以后,其执行结果如图7.25所示。
在这里插入图片描述
图7.25 使用NOT EXISTS的子查询
从图中可以看出,查询出的结果集数据在员工考勤数据表(T_KQ)中不存在。
7.5 相关子查询
子查询的执行要依赖于其上一层查询元组的当前值,也就是说,每次执行子查询时,都需要来自子查询外部的元组变量的值,这种子查询称之为相关子查询。前面介绍的EXISTS子查询,基本上全部都是相关子查询。
7.5.1 使用IN引入相关子查询
在IN子查询中可以使用相关子查询。
【上机实战】
在员工信息表(T_EMPLOY)中,查询员工编号(E_ID)、员工个姓名(E_NAME)、部门(E_BM)和工资(E_GZ)字段信息,同时满足员工编号为“1005”,并且该员工编号在员工考勤数据表(T_KQ)中存在的条件。

SELECT E_ID,E_NAME,E_BM,E_GZ
FROM  T_EMPLOY T
WHERE '1005' IN(SELECT E_ID FROM T_KQ WHERE E_ID=T.E_ID)
ORDER BY E_ID

代码执行以后,其执行结果如图7.26所示。
在这里插入图片描述
图7.26 使用IN引入相关子查询
上述代码是为了讲解如何使用IN引入相关子查询才这样写的,DBMS每次从员工信息表(T_EMPLOY)中取出一条记录,都要执行一次子查询。可以看出,相关子查询处理起来很烦琐。实际上,在员工信息表(T_EMPLOY)中直接使用WHERE条件语句也可以实现其需要的功能,代码如下所示:

SELECT E_ID,E_NAME,E_BM,E_GZ
FROM  T_EMPLOY T
WHERE E_ID= '1005'

7.5.3 在HAVING子句中使用相关子查询
在SQL中,DBMS使用HAVING子句中的查询条件删除不符合条件的数据行,来过滤查询结果中不想要的数据。本节中将讲解在HAVING子句中使用相关子查询作为查询条件的方法。
【上机实战】
在货物信息表(T_GOODS)中查询货物产地(G_PLACE)和每个货物产地的货物数量信息,同时要求这些产地的货物数量要小于采购信息表(T_STOCK)中每个采购货物产地(C_PLACE)的采购货物数量。为了便于读者进行学习比较,现将货物信息表(T_GOODS)和采购信息表(T_STOCK)中所有的数据信息显示出来。
显示货物信息表(T_GOODS)中的数据信息。

SELECT * FROM T_GOODS

显示采购信息表(T_STOCK)中的数据信息。

SELEC * FROM T_STOCK

上述代码执行以后,其运行结果分别如图7.27与图7.28所示。
在这里插入图片描述
图7.27 货物信息表(T_GOODS)中的数据信息
在这里插入图片描述
图7.28 采购信息表(T_STOCK)中的数据信息
在HAVING子句中使用相关子查询的语句如下所示。

SELECT T.G_PLACE,COUNT(*)
FROM T_GOODS T
GROUP BY T.G_PLACE
HAVING COUNT(*)<(SELECT COUNT(*) FROM T_STOCK WHERE C_PLACE IN
(SELECT C_PLACE FROM T_GOODS T1 WHERE T1.G_PLACE=T.G_PLACE))

代码执行以后,其执行结果如图7.29所示。
在这里插入图片描述
图7.29 在HAVING子句中使用相关子查询
代码中的HAVING子句中用到了相关子查询,下面分析一下该示例的执行过程。
(1)在执行SELECT语句时,DBMS首先执行FROM和GROUP BY子句,将T_GOODS表中的记录依据货物产地(G_PLACE)字段进行分组。
(2)然后DBMS处理来自中间表中的每一个分组信息,即依次对每个货物产地(G_PLACE)执行HAVING子句。
(3)在HAVING子句中,比较运算符右边是一个相关子查询,而相关子查询中又含有一个子查询。系统将从最底层的子查询“SELECT C_PLACE FROM T_GOODS T1 WHERE T1.G_PLACE=T.G_PLACE”开始执行,然后DBMS将执行其外层的相关子查询。
7.6 UNIQUE子查询
UNIQUE运算符通常与子查询结合使用,用于查询集合是否存在重复的元组。如果子查询的结果集中有重复的记录,则UNIQUE判式的值为False;否则如果子查询的结果中没有重复的记录,则UNIQUE判式的值为True。
【语法说明】
UNIQUE子查询的语句格式如下所示。

SELECT column_name
FROM table_name
WHERE [NOT] UNIOUE(subquery)

上述代码中,只要子查询subquery中返回的结果表存在重复记录,则子查询subquery语句的结果就为True。如果要使UNIQUE判式有意义,就应该在子查询中建立搜索条件以匹配子查询连接起来的两个表中的值。

说明:在SQL Server中,并不支持UNIQUE判式。

7.7 嵌套子查询
子查询本身也可以包含WHERE子句或HAVING子句,同样,子查询也可以出现在其他子查询当中。位于其他子查询内的子查询被称为嵌套的子查询。下面通过示例来讲解嵌套子查询的应用及执行过程。
【上机实战】
在货物信息表(T_GOODS)中查询货物产地(G_PLACE)和每个货物产地的货物数量信息,同时要求这些产地的名称信息在采购信息表(T_STOCK)中也存在,并且保证采购货物产地(C_PLACE)名称在货物信息表(T_GOODS)中也存在,其实现的代码如下所示。

SELECT T.G_PLACE,COUNT(*)
FROM T_GOODS T
GROUP BY T.G_PLACE
HAVING G_PLACE IN(SELECT C_PLACE FROM T_STOCK WHERE C_PLACE IN
(SELECT G_PLACE FROM T_GOODS T1 WHERE T1.G_PLACE=T.G_PLACE))

代码执行以后,运行结果如图7.30所示。
在这里插入图片描述
图7.30 嵌套子查询的使用
上述代码实际上实现的是通过嵌套子查询实现查询货物信息表(T_GOODS)和采购信息表(T_STOCK)中具有相同货物产地信息的交集。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HeartBest丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值