2021-4-6课程——SQL Server查询【4】

以为是讲完了再写博客总结,结果自己搞错了,以后一定得及时写,不然作业越拖越多。。
本篇主要记录嵌套插叙的学习,表依旧是之前的三张表,不再赘述,展示方式也一样。

嵌套查询

0.概念

在SQL语言中,一个select-from-where语句称为一个查询块,将一个查询块嵌套在另一个查询块的where子句或having短语的条件中的查询称为嵌套查询上层的查询块称为外层查询父查询,下层查询块称为内层查询子查询
PS:子查询的select语句中不能使用order by子句,order by子句只能对最终查询结果排序。

1.带有in谓词的子查询

例1:查询与“刘晨”在同一个系学习的学生。
可以先分布来完成此查询,然后再构造嵌套查询
①确定“刘晨”所在系名,结果为CS

select Sdept
from Student
where Sname='刘晨';

②查找所有在CS系学习的学生

select Sno,Sname,Sdept
from Student
where Sdept='CS';

在这里插入图片描述
改为嵌套查询,即将第一步的查询嵌入到第二步的查询条件中。

select Sno,Sname,Sdept
from Student
where Sdept in
	(select Sdept
	 from Student
	 where Sname='刘晨');

2021-4-6课程——SQL Server查询【4】_第1张图片
在该例中,子查询的查询条件不依赖于父查询,称为不相关子查询。查询时是由内向外的,子查询的结果用于建立其父查询的查找条件。

==变式:==本例中的查询也可以用自身连接来完成,查询结果一样。

select S1.Sno,S1.Sname,S1.Sdept
from Student S1,Student S2
where S1.Sdept=S2.Sdept and S2.Sname='刘晨';

例2:查询选修了课程名为“信息系统”的学生学号和姓名
解题方法:本查询涉及学号、姓名和课程名三个属性,学号和姓名存放在Student表中,课程名存放在Course表中,两个表并无直接联系,必须通过SC表建立,所以一共涉及三张表。

select Sno,Sname -- ③最后再Student关系中取出Sno和Sname
from Student
where Sno in
	(select Sno -- ②然后在SC关系中找出选修了3号课程的学生学号
	 from SC
	 where Cno in
		(select Cno -- ①首先在Course关系中找出信息系统的课程号,结果为3
		 from Course
		 where Cname='信息系统'
		 )
	);

也可以使用连接查询,对应SQL语句如下

select Student.Sno,Sname
from Student,SC,Course
where Student.Sno=SC.Sno and
	SC.Cno=Course.Cno and
	Course.Cname='信息系统';

二者查询结果一致,如下
2021-4-6课程——SQL Server查询【4】_第2张图片
上述的两个例子都是不相关子查询的,下面是相关子查询的,即子查询的查询条件依赖于父查询,整个查询语句称为相关嵌套查询

2.带有比较运算符的子查询

该类查询是指父查询与子查询之间用比较运算符进行连接,当用户确切知道内层查询返回的是单个值时,就可以使用> < >=等这类的比较运算符。

应用:上述例1中由于一个学生只可能在一个系学习,即子查询的结果是一个值,所以可以用=代替in

select Sno,Sname,Sdept
from Student
where Sdept=
	(select Sdept
	 from Student
	 where Sname='刘晨'
	 );

例:找出每个学生超过他自己选修课程平均成绩的课程号
内层查询是求每个学生所有选修课程的平均成绩,至于是哪个学生的平均成绩要看参数x.Sno的值,即子查询是依赖于父查询的,所以为相关子查询

select Sno,Cno
from SC x
where Grade>=(select avg(Grade)
			  from SC y
			  where y.Sno=x.Sno);

2021-4-6课程——SQL Server查询【4】_第3张图片
为了便于自己的理解,下面将书上的关于这一例子(实际上是它的内部执行原理)写上。
该语句的一种可能的执行过程采用以下三个步骤:
①从外层查询中取出SC的一个元组x,将元组x的Sno值(201215121)传送给内层查询

select avg(Grade)
from SC y
where y.Sno='201215121';

②执行内层查询,得到88(近似值),用该值代替内层查询,得到外层查询

select Sno,Cno
from SC x
where Grade>=88;

③执行这个查询,得到结果

201215121 1
201215121 3

然后外层查询取出下一个元组重复作上述①-③步骤的处理,直到外层的SC元组全部处理完毕。

3.带有any(some)或all谓词的子查询

子查询返回单值时可以用比较运算符,但返回多值时要使用any(或some,视系统定)或all谓词修饰。any是某个值,而all是所有值

例1:查询非计算机科学系中比计算机科学系任意一个学生年龄小的学生姓名和年龄(随便一个都可以,所以是any)

select Sname,Sage
from Student
where Sage<any(select Sage
			   from Student
			   where Sdept='CS')
and Sdept!='CS'; -- 也可将!=改为<>

2021-4-6课程——SQL Server查询【4】_第4张图片

变式:由于是小于随便一个的年龄即可,那么只要小于计算机科学系的最大年龄即可

select Sname,Sage
from Student
where Sage<(select max(Sage)
			   from Student
			   where Sdept='CS')
and Sdept!='CS'; -- 也可将!=改为<>

例2:查询非计算机科学系中比计算机科学系所有学生年龄都小的学生姓名及年龄(所有,使用all)

select Sname,Sage
from Student
where Sage<all(select Sage
			   from Student
			   where Sdept='CS')
and Sdept!='CS'; -- 也可将!=改为<>

2021-4-6课程——SQL Server查询【4】_第5张图片
同理,也可是更改,由于是小于所有的,则需要小于最小的,使用聚集函数min即可。

4.带有exists谓词的子查询

exists代表存在量词,带有exists谓词的子查询不返回任何数据,只产生逻辑真值true或false。

例1:查询所有选修了1号课程的学生姓名

select Sname
from Student
where exists
	(select *
	 from SC
	 where Sno=Student.Sno and Cno='1');

2021-4-6课程——SQL Server查询【4】_第6张图片
使用exists后,若内层查询结果非空,则外层的where子句返回真值,否则返回返回假值,由exists引出的子查询,其目标列表达式通常都用*,给出实际列名无实际意义。

例2:查询没有选修1号课程的学生姓名
可以使用not exists

select Sname
from Student
where not exists
	(select *
	 from SC
	 where Sno=Student.Sno and Cno='1');

2021-4-6课程——SQL Server查询【4】_第7张图片

PS:所有带in谓词,比较运算符,any和all谓词的子查询都能用带exists的等价替换

例3:查询选修了全部课程的学生姓名
由于没有全称量词,所以可以将题目转换为:查询这样的学生,没有一门课程是他不选修的。

select Sname
from Student
where not exists
	(select *
	 from Course
	 where not exists
		(select *
		 from SC
		 where Sno=Student.Sno
		 and Cno=Course.Cno));

例1:查询至少选修了学生201215122选修的全部课程的学生号码
可是用逻辑蕴涵来表达:查询学号为x的学生,对所有的课程y,只要201215122学生选修了课程y,则x也选修了y。但是SQL中没有蕴涵,可以对其进行转换,为:不存在这样的学生,学生201215122选修了y,而学生x没有选

select distinct Sno
from SC SCX
where not exists
	(select *
	 from SC SCY
	 where SCY.Sno='201215122' and
		not exists
		(select *
		 from SC SCZ
		 where SCZ.Sno=SCX.Sno and
			SCZ.Cno=SCY.Cno));

2021-4-6课程——SQL Server查询【4】_第8张图片

课程感悟:
觉得exists的有点难理解,经常是懂了又不懂,不懂又弄懂,真正理解它,还需要知道执行过程,如何把不存在的蕴涵或全称关系等价的转换为可以用存在量词表示的意思,这也是一个难点,路漫漫其修远兮,还得继续加油啊!

你可能感兴趣的:(SQL,Server+C#)