携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天
嵌套查询讲解
嵌套查询的分类: 1、不相关子查询 2、相关子查询
一、不相关子查询
1、子查询的查询条件不依赖于父查询
2、是由里向外逐层处理。即每个子查询在上一级查询处理之前求解,子查询的结果用于建立其父查询的查找条件。
例1、查询学生表与“古月”是老乡的全部同学的信息
两步完成:第一步查古月的籍贯 第二步 查所有这个籍贯的学生
将第一步查询嵌入道第二步查询中
确切知道内层查询返回单值时,可用比较运算符(> = < >= <= !=<>)
select * from dbo.学生1
where 籍贯=(select 籍贯 from dbo.学生1 where 姓名='古月')
例2、查询学习了课程号为“002”学生的姓名(两种方法)
注意:有些嵌套查询可以用连接查询实现的
注意:=1个 , in多个
select 姓名
from 学生1
where 学号 in (select 学号 from 成绩1 where 课程号 ='002')
例3、查询选修了课程名为“数据库技术”的学生的学号和姓名(两种方法)
select 学号,姓名
from 学生1
where 学号 in
(select 学号 from 成绩1 where 课程号 in (select 课程号 from 课程1 where 课程名='高等数学') )
order by 学号
二、相关子查询:
1、子查询的查询条件依赖于父查询
2、①首先取外层查询中表的第一条记录,根据它,与内层查询相关的属性值处理内层查询,若where子句返回值为真,则取此记录放入结果表中。
②然后再取外层表的下一条记录。
③重复这一过程,直至外层表全部检查完为止。
例4、根据成绩表,查询出每个学生超过所有课程平均分的学号、课程号、成绩(不相关子查询)
select *
from 成绩1
where 成绩>(select avg(成绩) from 成绩1)
select avg(成绩) from 成绩1 平均成绩70
例5、根据成绩表,查询出每个学生超过本人所有课程平均分的学号、课程号、成绩(相关子查询)
select *
from 成绩1 a
where 成绩>(select avg(成绩) from 成绩1 b where a.学号=b.学号)
嵌套查询的谓词
1、比较运算符的子查询
2、in谓词的子查询
3、any(some) 或all谓词的子查询:any任意一个值,all所有值 需要配合运算符使用
4、exists或not exists谓词的子查询
exists谓词:存在 (不关心结果,只关心存在不存在)—相关子查询
①带有exists的子查询不返回任何数据,只产生逻辑真或逻辑假
l 若内层查询结果非空,则外层的where子句返回真值
l 若内层查询结果为空,则外层的where子句返回假值
②由exists引出的子查询,其目标列表达式通常都用“*”,应为返回真假,给出列名无实际意义
not exists谓词:
若内层查询结果非空,则外层的where子句返回假值
若内层查询结果为空,则外层的where子句返回真值
例6、查询学生表里,比高考成绩平均分高的学生的学号、姓名和高考成绩
select 学号,姓名,高考成绩
from 学生1
where 高考成绩>(select avg(高考成绩) from 学生1)
例7、查询学生表里,比吉林省长春市高考成绩都要高的学生的学号、姓名、高考成绩
select 学号,姓名,高考成绩,籍贯
from 学生1
where 高考成绩>all(select 高考成绩 from 学生1 where 籍贯='吉林省长春市')
比吉林省长春市所有的都高 ,大于最高值(605)
select 学号,姓名,高考成绩,籍贯
from 学生1
where 高考成绩<all(select 高考成绩 from 学生1 where 籍贯='吉林省长春市')
比吉林省长春市所有的都低 ,小于最低值(415)
select 学号,姓名,高考成绩,籍贯
from 学生1
where 高考成绩>any(select 高考成绩 from 学生1 where 籍贯='吉林省长春市')
大于最低值
select 学号,姓名,高考成绩,籍贯
from 学生1
where 高考成绩<any(select 高考成绩 from 学生1 where 籍贯='吉林省长春市')
小于最低值
select 学号,姓名,高考成绩,籍贯
from 学生1
where 高考成绩<any(select 高考成绩 from 学生1 where 籍贯='吉林省长春市')
and 籍贯!='吉林省长春市' (注意这是夫查询块中的条件)
例8、查询学习了003号课程的学生姓名(三种方法实现)
select 姓名
from 学生1
where exists
(select * from 成绩1 where 课程号='003')
写什么课程号结果都是8个人,因为这个子查询结果永远为真
select 姓名
from 学生1
where exists
(select * from 成绩1 where 课程号='003' and 学号=学生1.学号)
select 姓名
from 学生1
where 学号 in
(select 学号 from 成绩1 where 课程号='003' )
select 姓名
from 学生1 join 成绩1 on 学生1.学号=成绩1.学号
where 课程号='003'
例9、查询没有学习003号课程的学生姓名(几种方法实现)
select 姓名
from 学生1
where not exists
(select * from 成绩1 where 课程号='003' and 学号=学生1.学号)
select 姓名
from 学生1
where 学号 not in
(select 学号 from 成绩1 where 课程号='003' )
总结:不同形式的查询间的替换
一些带 exists或not exists的子查询不能被其他形式的子查询等价替换
所有带in谓词、比较运算符、any和all谓词的子查询都能用带exists谓词的子查询等价替换。