3.使用子查询访问和修改数据
子查询和连接查询一样提供了使用单个查询访问多个表中的数据的方法。子查询在其他结果的基础上提供一种有效地方式来表示WHERE子句的条件。子查询是一个SELECT语句,它定义在SELECT、INSERT、UPDATE或DELECT语句或者另一个子查询中。子查询的SELECT语句可与外部查询指向不同的表。
嵌套的子查询或嵌套的SELECT语句是指包含一个或多个子查询的SELECT语句。子查询可嵌套在外部的SELECT、INSERT、UPDATE或DELECT语句的WHERE或HAVING子句或其他子查询内。如果嵌套了多层,则总是首先评估最内层的查询。子查询也成为内查询,也可以嵌套任意数量的子查询。任何可以使用表达式的地方都可以使用子查询,只要它返回的是单个值。
3.1返回多行的子查询
子查询是在SELECT语句中的WHERE子句实现的,可以把WHERE子句中的子查询分成两类:返回多行的子查询和只返回一个值的子查询。
3.1.1使用IN关键字
可以使用IN关键字来判断一个表中指定列的值是否包含在已定义的列表中,或者在另一个表中。在前一种情况下,可以指定列名、IN关键字和用来指定列进行比较的值列表;在后一种情况下,可以指定列名、IN关键字和引用另外一个表的子查询。
举例来说,从数据库”销售管理系统“中,查询(没有)接待过顾客的业务员的相关信息。
SELECT 业务员姓名,家庭住址,电话
FROM 业务员信息
WHERE 业务员编号 (NOT)IN
( SELECT 所属业务员编号
FROM 客户信息 )
3.1.2使用EXISTS关键字
在一些情况下,只需要返回一个真值或者假值。EXISTS关键字只注重子查询是否返回行。如果子查询返回一个或多个行,那么EXISTS便返回为真,否则为假。子查询必须是一个真实的值,它用来比较不同表中两列的值。
使用EXISTS关键字引入一个子查询时,就相当于进行一次是否存在的测试。它的作用是在WHERE子句中测试子查询返回的行是否存在。EXISITS子查询实际上不产生任何数据,它只返回TRUE或FALSE。
举例来说,在数据库”销售管理系统“中,查询”供应商信息“表中,”供应商编号“为1006的供应商所提供的商品的相关信息。
SELECT 商品名称,产地,单价
FROM 商品信息
WHERE EXISITS
(SELECT *
FROM 供应商信息
WHERE 供应商编号=商品信息.供应商编号
AND 供应商编号=1006)
NOT EXISTS和EXISTS相反,如果子查询没有返回行,则满足NOT EXISTS中的WHERE子句,即在子查询返回行时,NOT EXISTS查询成功。
举例来说,在”珠宝销售系统“中,查询在”销售信息“中没有提供珠宝并且其所在城市不是北京市的珠宝商的相关信息,并按”珠宝商所在城市“进行排序。
SELECT 珠宝商姓名,珠宝商地址,珠宝商所在城市,电话
FROM 珠宝商信息
WHERE NOT EXISTS
(SELECT *
FROM 销售信息
WHERE 珠宝商编号=珠宝商信息.珠宝商编号
)
AND 珠宝商所在城市<>'北京市'
ORDER BY 珠宝商所在城市
3.1.3使用比较运算符
子查询可以由一个比较运算符引入。与使用关键字IN引入的子查询一样,由比较运算符与一些关键字引入的子查询返回一个值列表。
SQL支持的在子查询中使用到的比较运算符有ANY、SOME和ALL。ANY和SOME关键字只注重是否有返回值满足搜索条件,它们的含义相同,可以相互替换使用。ALL关键字只注重是否所有的返回值都满足搜索条件。
举例来说,在数据库”销售管理系统“的”出库单明细信息“表中,查询”出库商品金额“大于任意一个”入库单明细信息“表中”入库商品金额“高于10000的出库单的相关信息。
SELECT *
FROM 出库单明细信息
WHERE 出库单商品金额 > ANY
(SELECT 入库商品金额
FROM 入库单明细信息
WHERE 入库商品金额 > 10000)
为了方便学习两者使用情况,我们进行对比学习,下面就举一个相同的例子,在数据库”销售管理系统“的”出库单明细信息“表中,查询”出库商品金额“大于所有”入库单明细信息“表中”入库 商品金额“低于10000的出库单的相关信息。
SELECT *
FROM 出库单明细信息
WHERE 出库单商品金额 > ALL
(SELECT 入库商品金额
FROM 入库单明细信息
WHERE 入库商品金额 < 10000)
3.2返回单个值的子查询
这样的子查询只返回一个值,然后将一列值与单个子查询返回的值进行比较,这时可以使用比较运算符。
由未修改的比较运算符(后面不跟ANY或ALL的比较运算符)引入的子查询必须返回单个值而不是值列表。
举例来说,在”珠宝销售系统“中,查询与”消费者编号“为27的消费者同处一个城市的珠宝商相关信息,要求以列”珠宝商姓名“、”珠宝商地址“、”珠宝商所在城市“和”电话“的形式返回查询结果。
SELECT 珠宝商姓名,珠宝商地址,珠宝山所在城市,电话
FROM 珠宝商信息
WHERE 珠宝商所在城市=
(SELECT 消费者所在城市
FROM 顾客信息
WHERE 消费者编号=27
)
由于聚集函数可以返回一个单值,所以可以在子好擦寻中包含聚集函数。
举例来说,在数据库”销售管理系统“中的”商品信息“表中,查询单价大于平均价格的商品的相关信息。要求以列”商品名称“、”产地“和”单价“的形式返回查询结果。
SELECT 商品名称,产地,单价
FROM 商品信息
WHERE 单价>
(SELECT AVG(单价)
FROM 商品信息
)
3.3使用相关子查询
在之前说明的子查询中,SQL只对子查询进行一次评估,然后替换搜索条件中的子查询结果,以及依据搜索条件的值来对外部查询进行评估。但是,有些子查询的执行过程依赖于值得外部查询。结果是,反复的执行子查询,对外部查询选择的每行都执行一次。这样的子查询称为相关子查询。
因为相关子查询依赖于其结果的外部查询,所以他们不能进行单独评估。相关子查询的WHERE子句引用外部查询的FROM子句中的表。也就是说,相关子查询是一个在外部查询中包含表的引用外部查询的FROM子句中的表。也就是说,相关子查询是一个在外部插叙中包含表的引用的子查询,它不能再外部查询之前求值。
举例来说,在”销售管理系统“中,查询由”供应商名称“为”北京世纪葵花“提供的商品的相关信息。要求以列”商品名称“、”产地“和”单价“的形式返回查询结果。
SELECT 商品名称,产地,单价
FROM 商品信息
WHERE '北京世纪葵花' IN
(SELECT 供应商名称
FROM 供应商信息
WHERE 商品信息.供应商编号=供应商信息.供应商编号
)
在相关子查询中,也可以为表指定表名,利用别名来代替表名。但是如果对于同一个表进行相关子查询时,则必须为表指定别名。
举例来说,在”珠宝营销系统“的”顾客信息“表中,查询顾客所居住的不同城市。
SELECT DISTINCT A.消费者所在城市
FROM 顾客信息 A
WHERE A.消费者所在城市 IN
(SELECT B.消费者所在城市
FROM 顾客信息 B
WHERE A.消费者编号<>B.消费者编号
)
上述子查询的语句等同于下面的自连接查询语句(关于自连接的相关介绍,请查阅这里),将该自连接查询语句运行后,其查询结果与上述的子查询语句的结果完全相同。
SELECT DISTINCT A.消费者所在城市
FROM 顾客信息 A INNER JOIN 顾客信息 B
ON A.消费者所在城市=B.消费者所在城市
AND A.消费者编号<>B.消费者编号
3.4使用嵌套子查询
前面介绍了只有一个子查询的SELECT语句,然而,在SELECT语句中还可以包含多个子查询,即一个子查询中还包含其它子查询,这样的查询称为嵌套子查询。
在SELECT语句中使用多个子查询的一种方法是把它们作为这个语句的不同组成部分。例如,一个WHERE子句可能含有两个关键字来引导两个子查询语句。还有一种在SELECT语句中使用多个子查询的方法是把一个子查询嵌套到另一个子查询中。
举例来说,在数据库“销售管理系统”中,查询客户在2005年6月1日至2005年12月31日之间购买商品时,接待客户的业务员的相关信息。要求以列“业务员姓名”、“家庭住址”和“电话”的形式返回查询结果。
SELECT 业务员姓名,家庭住址,电话
FROM 业务员信息
WHERE 业务员编号 IN
(SELECT 所属业务员编号
FROM 客户信息
WHERE 客户编号 IN
(SELECT 客户编号
FROM 出库单信息
WHERE 出库日期 BETWEEN '2005-6-1' AND '2005-12-31'
)
)
上述语句运行顺序为:绿色部分,紫色部分,蓝色部分,即由内到外,逐次查询。
3.5使用子查询修改数据
子查询还可以用来修改数据库中的数据。使用子查询修改数据主要是通过下面3个关键字来实现INSERT、UPDATE和DELETE。
3.5.1插入数据
INSERT语句可以向已有表中添加数据。它可以直接向表中插入数据,也可以用视图向隐含表中插入数据。如果要在INSERT语句中使用子查询,必须把它作为VALUES子句中定义的一个值。
举例来说,在数据库“销售管理系统”中的“业务员信息”表中增加一名业务员的一行新数据,该行数据中“业务员编号”为1009,“业务员姓名”、“家庭住址”和“电话”来自“客户信息”表中“客户编号”为1008的“客户姓名”、“客户地址”和“联系电话”。
INSERT INTO 业务员信息 VALUES
(1009,
(SELECT 客户姓名
FROM 客户信息
WHERE 客户编号=1008),
(SELECT 客户地址
FROM 客户信息
WHERE 客户编号=1008),
(SELECT 联系电话
FROM 客户信息
WHERE 客户编号=1008)
)
再执行下面语句进行查看:SELECT * FROM 业务员信息
在INSERT语句中使用子查询向表中插入数据时,必须确定子查询的返回结果只能返回一个值。如果返回的查询结果中多于一个值,就会出现错误,并且子查询中返回的单个值必须和目标列的数据类型及其他限制一致。
3.5.2更新数据
UPDATE语句允许修改表中已有数据。和INSERT语句一样,可以直接对表中的数据进行修改。如果视图可更新,也可以通过视图进行修改。要在UPDATE语句中使用子查询,子查询则由WHERE子句引入。
举例来说,在上个例子中,将数据库“销售管理系统”的“业务员信息”表中添加的那一行数据所对应的“业务员姓名”、“家庭住址”和“电话”分别更改为“赵奇”、“北京市西城区”和“13585452343”。
UPDATE 业务员信息
SET 业务员姓名='赵奇',家庭住址='北京市西城区',电话='13585452343'
WHERE 业务员姓名=
(SELECT 客户姓名
FROM 客户信息
WHERE 客户姓名='薛红林'
)
再执行下面语句进行查看:SELECT * FROM 业务员信息
3.5.3删除数据
DELETE语句实现的功能是删除数据库表中的数据。在DELETE语句中的WHERE子句中使用子查询与UPDATE语句相似。
举例来说,将数据库“销售管理系统”的“业务员信息”表中插入的那一行数据删除。
DELETE 业务员信息
WHERE 业务员姓名=
(SELECT 客户姓名
FROM 客户信息
WHERE 客户编号=1008
)
4.学习小结
数据库的查操作是数据库的重点学习部分,在这几部分的学习和总结的过程中,深感乏力,无论知识体系的庞大还是其中相关联系的错综复杂,都是十分重要的,却也是最难以理解和掌握的。
自己也是用了半月的时间把数据库的查操作的总结用最后的时间总结了出来,做一分享,当然,不得不说的是,对于数据库的相关知识,希望努力去实践,在操作中体会用法,以便更好地掌握其要领,也希望自己今后可以做到更好。