标准SQL语句(5) --- 表的查询(3)

声明:本文使用到的数据表请参看本博客的另一篇文章:标准SQL语句(2)--- 表的增删改 


引言

在where子句中包含一个形如select-from-where的查询块,此查询块称为子查询或嵌套查询,包含子查询的语句称为父查询或外部查询。

嵌套查询可以将一系列简单查询构造成复杂查询,增强查询能力。子查询的嵌套层次最多可达到255层,以层层嵌套的方式构造查询充分体现了SQL的“结构化”的特点。


嵌套查询在执行时由里向外处理,每个子查询是在上一级外部查询处理之前完成的,父查询要用到子查询的结果。


1. 返回一个值的子查询

当子查询的返回值只有一个时,可以使用比较运算符(=,>,<,>=,<=,!= )将父查询和子查询连接起来。


例:查询与“刘伟”老师职称相同的教师号、姓名。

select TNo, TN from T where Prof=(select Prof from T where TN='刘伟')

2.返回一组值的子查询

如果子查询的返回值不止一个,而是一个集合时,则不能直接使用比较运算符,可以在比较运算符和子查询之间插入any或all。其具体含义详解下面个例。


1) 使用any


例1:查询讲授课程号为C5的教师姓名。

select TN from T where T.TNo = any( select TC.TNo from TC where CNo='C5' )

注:TNo前面的表名可以不加,这里只做区分。


例2:查询其他系中比计算机系某一教师工资高的教师的姓名和工资。

select TN, Sal from T where Dept <> '计算机' and Sal > any( select Sal from T where Dept='计算机')

注:<>和!=是等效的,据说<>是SQL最初的标准,而!=是后来引入的。


2) 使用in

可以使用in代替“=any”


例:查询讲授课程号为C5的教师姓名(使用in)。

select TN from T where TNo in (select TNo from TC where CNo='C5')

3) 使用all

all的含义为全部。


例1:查询其他系中比计算机系所有教师工资都高的教师姓名和工资。

select TN,Sal from T where Dept<>'计算机' and Sal > all( select Sal from T where Dept='计算机')

也可以这么写:

select TN,Sal from T where Dept<>'计算机' and Sal > (select max(Sal) from T where Dept='计算机')

例2:查询不讲授课程号为C5的教师姓名。

select TN from T where TNo <> all(select TNo from TC where CNo='C5') 

也可以这么写:

select TN from T where 'C5'<> all(select CNo from TC where TNo=T.TNo)

注: <>all的含义为不等于子查询结果中的任何一个值,也可以使用not in 代替<>all。


相关子查询

子查询包含普通子查询和相关子查询。前面所讲的子查询均为普通子查询。


子查询的查询条件中引用了父查询表中的属性值,就称该查询为相关子查询。


首先,我们来看看普通子查询和相关子查询这两者有何不同。


1) 执行顺序不同

普通子查询的执行顺序是:首先执行子查询,然后把子查询的结果作为父查询的查询条件的值。普通子查询只执行一次,而父查询所涉及的所有记录行都与其查询结果比较以确定查询结果集合。


相关子查询的执行顺序是:首先选取父查询表中的第一条记录,内部的子查询利用此行中相关的属性值进行查询,然后父查询根据子查询返回的结果判断此行是否满足查询条件。如果满足条件,则把该行放入父查询的查询结果集中。重复执行这一过程,直到处理完父查询表中的每一行数据。


下面举几个相关子查询的例子。


4) 使用exists

exists是表示存在的量词,带有exists的子查询不返回任何实际数据,它只得到逻辑值“真”或“假”。 当子查询的查询结果集合非空时,外层的where子句返回真值,否则返回假值。not exists则正好相反。

含有in的查询通常可以用exists表示,但反过来则不一定。


例1:(使用exists语句来完成)查询讲授课程号为C5的教师姓名。

select TN from T where exists (select * from TC where TNo=T.TNo and CNo='C5')


例2:查询没有讲授课程号为C5的教师姓名。

select TN from T where not exists (select * from TC where TNo=T.TNo and CNo='C5')

例3: 查询选修所有课程的学生姓名。

select SN from S where not exists (select * from C where not exists (select * from SC where SNo=S.SNo and CNo=C.CNo ))

释义: 本例可以理解为,选出这样的一些学生名单,在SC表中不存在他们没有选修课程的记录。



其他查询


1. 合并查询

合并查询就是使用union操作符将来自不同查询的数据组合起来,形成一个具有综合信息的查询结果。union操作会自动将重复的数据行剔除。

必须注意的是,参加合并查询的各个子查询的使用的表结构应该相同,即各个子查询中的数据数目和对应的数据类型都必须相同。


例:从SC数据表中查询出学号为“S1”同学的学号和总分,再从SC数据表中查询出学号为“S5”的同学的学号和总分,然后将两个查询结果合并成一个结果集。

select SNo as '学号', sum(Score) as '总分' from SC where SNo='S1' group by SNo  
union 
select SNo as '学号', sum(Score) as '总分' from SC where SNo='S5' group by SNo 

2.存储查询结果到表中

使用select ... into 语句可以将查询结果存储到一个新建的数据库表或临时表中。


例:从SC数据表中查询出所有同学的学号和总分,并将查询结果存放到一个新的数据表Cal_Table中。

select SNo as '学号', sum(Score) as '总分' into Cal_Table from SC group by SNo

在本例中,如果将into Cal_Table改为into #Cal_Table,则查询的结果被存放到一个临时表中,临时表只存储在内存中,并不存储在数据库中,所以存在的时间非常短。



  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值