数据库作业7:select / 多表查询(连接查询、嵌套查询)

以下是课本上关于 多表查询 操作的一些试题

老规矩,先写总结:

  • 多表连接中注意事项和小结:
  1. 多表连接时候,当属性列在查询的多个表里面是唯一的就可以省略表名前缀,否则必须加上表名前缀;
  2. 一张表进行自身连接时,可以给表起不同的名称来加以区分;
  3. 使用外连接,可以使连接操作中的表中含有但是不满足连接条件的也可以输出NULL值。
  4. 左外连接列出左边的关系,右外连接列出右边关系中所有的元组(见例 [ 3.53 ] );点我跳转
  5. 关系数据库管理系统在执行多表连接时,通常是先进行两个表的连接操作,再将其连接结果与第三个表进行连接;
  6. 在SQL语言中,一个select – from – where语句称为一个査询块。将一个査询块嵌套在另一个査询块的 where子句 或 having短语 的条件中的査询称为嵌套査询
  7. 上层的査询块称为外
层査询或父查询,下层査询块称为内层査询或子査询。
  8. 一个子査询中还可以嵌套其他子査询。但是子査询的SELECT语句中不能使用order by子句,order by子句只能对最终
査询结果排序。
  9. 子查询的查询条件不依赖于父查询,称为不相关子查询(见 [ 例3.55 ]点我跳转
  10. 不相关子查询的求解方法:一般是先执行子查询,后执行父查询;
  11. 子查询的条件依赖于父查询,称为相关子查询 (见 [ 例3.57 ])点我跳转
  12. 有些嵌套查询可以用连接运算替代,能够用连接运算表达的査询尽可能采用连接运算。
相关子查询的求解方法 点我跳转
谓词any 、all使用说明 点我跳转
聚集函数和 any 、all 的对应用法 点我跳转
在写例题之前我们看一下用到的表的结构和数据(有三张表):


在这里插入图片描述
Course表如下:

在这里插入图片描述


Student表如下:

在这里插入图片描述


SC表如下:

在这里插入图片描述

[例3.49] 查询每个学生及其选修课程的情况。
        学生信息存储在Student表中,学生选课情况存放在SC表中,所以本査询实际上涉及Student与SC两个表。这两个表之间的联系是通过公共属性Sno实现的。

       代码如下:

select Student.* , SC.* 
	from Student , SC  
	where Student.Sno = SC.Sno; 

结果如下图:

在这里插入图片描述
[例3.50] 对【例3.49】用自然连接完成。

       代码如下:

select Student.Sno , Sname , Ssex , Sage , Sdept , Cno , Grade 
	from Student , SC 
	where Student.SNo = SC.Sno;

结果如下图:

在这里插入图片描述

       当属性列在查询的所有表里面是唯一的就可以省略表名前缀,否则必须加上表名前缀。
       本例中,由于 Sname, Ssex, Sage, Sdept,Cno 和 Grade 属性列在 Student 表与 SC 表中是唯一的,因此引用时可以去掉表名前缀;而Sno在两个表都出现了,因此引用时须加上表名前綴。

[例3.51] 査询选修2号课程且成绩在90分(包含90分)以上的所有学生的学号和姓名。

       代码如下:

select Student.Sno , Sname 
	from Student , SC 
	where Student.Sno = SC.Sno 
		and SC.Cno = '2' 
		and SC.Grade >= 90;

结果如下图:

在这里插入图片描述


       该査询的一种优化(高效)的执行过程是,先从SC中挑选出Cno=2并且Grade>=90的元组形成一个中间关系,再和Student中满足连接条件的元组进行连接得到最终的结果关系。

       优化查询语句代码如下:

select Student.Sno , Sname 
	from Student 
	where Student.Sno = 
		(
			select SC.Sno from SC 
			where SC.Cno = '2'
				and SC.Grade >= 90
		);

结果如下:

在这里插入图片描述
       我们可以看到,和原方法查询结果一致。

[例3.52] 査询每一门课的间接先修课(即先修课的先修课).
       在Course表中只有每门课的直接先修课信息,而没有先修课的先修课。要得到这个信息,必须先对一门课找到其先修课,再按此先修课的课程号査找它的先修课程。这就要将Course表与其自身连接

       代码如下:

select first.Cno , second.Cpno 
	from Course first , Course second 
	where first.Cpno = second.Cno;

       在此,我们为Course表取了两个别名(first 和 second);


结果如下图:

在这里插入图片描述

[例 3.53] 在我们常用的连接操作中,满足条件的元组才可以作为结果进行输出,不满足条件的就会被舍弃。如果我们想让元组不被舍弃,并且输出为NULL值。我们就要用到外连接
       接下来对例【3.49】修改,输出被舍弃的和没被舍弃的结果:

       代码如下:

select Student.Sno , Sname , Ssex , Sage , Sdept , Cno , Grade 
	from Student left outer join SC 
	on(Student.Sno = SC.Sno);

结果如下图:

在这里插入图片描述
       例【3.49】输出结果我搬到下面:

在这里插入图片描述
       我们可以看到,被舍弃的元组又被输出了出来。

       我们要是想去除重复的值可以用修改为以下语句:

from Student left outer join SC using(Student.Sno = SC.Sno);

       左外连接列出左边的关系(本例题),右外连接列出右边关系中所有的元组,右连接运行结果如图:

在这里插入图片描述

[例3.54] 査询每个学生的学号、姓名、选修的课程名及成绩。

       此次查询涉及了三张表,代码如下:

select Student.Sno , Sname , Cname , Grade 
	from 	Student , SC , Course 
	where	Student.Sno = SC.Sno 
			and SC.Cno = Course.Cno;

结果如下图:

在这里插入图片描述
       关系数据库管理系统在执行多表连接时,通常是进行两个表的连接操作,再将其连接结果与第三个表进行连接。

[例3.55] 査询与“刘晨”在同一个系学习的学生。
       在这里我们用到嵌套查询,什么是嵌套查询呢?
       在SQL语言中,一个select – from – where语句称为一个査询块。将一个査询块嵌套在另一个査询块的 where子句 或 having短语 的条件中的査询称为嵌套査询 ,此题目中,我们先分步来完成此査询,然后再构造嵌套査询:

  1. 先确定“刘晨”所在系名,代码如下:
select Sdept 
	from Student 
	where Sname = '刘晨';

结果如下:
在这里插入图片描述

  1. 查找所有在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 = '刘晨'
		);

结果如下图:

在这里插入图片描述
       上层的査询块称为外
层査询或父查询,下层査询块称为内层査询或子査询。
       
一个子査询中还可以嵌套其他子査询。但是子査询的SELECT语句中不能使用order by子句,order by子句只能对最终
査询结果排序。
       显然,嵌套查询可以说是一步步地简化复杂的查询。
       本例题中,子查询的查询条件不依赖于父查询,称为不相关子查询
       求解方法一般是先执行子查询,后执行父查询。

[例3.56] 查询选修了课程名为“信息系统”的学生学号和姓名。


       本查询涉及三个关系,我们用两种方法实现,第一种方法代码如下:

select Sno , Sname 
	from Student 
	where Sno in 
		(
			select Sno 
			from SC 
			where Cno in 
				(
					select Cno 
					from course 
					where Cname = '信息系统'
				)
		);

结果如下图:

在这里插入图片描述

  • 这里我们同样可以用第二种方法(连接查询)实现,代码如下:
select Student.Sno , Sname 
	from  Student , SC , Course 
	where Student.Sno = SC.Sno 
		  and SC.Cno = Course.Cno	
		  and Course.Cname = '信息系统';

结果如下图:

在这里插入图片描述
       我们发现两种结果相同,证明查询正确。
       有些嵌套查询可以用连接运算替代,能够用连接运算表达的査询尽可能采用连接运算。

[例3.57] 找出每个学生超过(或等于)他自己选修课程平均成绩的课程号。

       此例题中的子查询为相关子查询(子查询的查询条件以来于父查询),代码如下:

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

结果如下图:

在这里插入图片描述

  • 求解相关子查询和求解不相关子查询不同,内层查询由于与外层查询有关,所以必须反复求值。比如这道题目的一种可能求解过程如下:
  1. 从外层查询中取出SC的一个元组 x ,将元组 x 的Sno值传递给内层查询。
  2. 执行内层查询,可以得到一个值,用这个值替代内层查询,代入到外层查询中。
  3. 执行查询,得到部分结果
  4. 判断最外层SC元组是否处理完毕。
    4.1 没处理完毕时:外层查询取出下一个元组,重复上述步骤。
    4.2 处理完毕:输出结果,结束。

[例3.58] 査询非计算机科学系中比计算机科学系任意一个学生年龄小的学生姓名和年龄。

       代码如下:

select Sname , Sage 
	from Student 
	where Sage < any
	(
		select Sage 
		from Student 
		where Sdept = 'CS'
	)
and Sdept <> 'CS';

结果如下图:

在这里插入图片描述

  • 这里我们用到了 any 谓词,怎么用呢?
  1. 当子查询返回单个值的时候我们可以用比较运算符,但是返回多个值的时候就要用到我们的 any 或者 all 谓词。

  1. 使用谓词 any 与 all 必须同时使用 比较运算符。如下表:
符号 效果
> any 大于子査询结果中的某个值
> all 大于子査询结果中的所有值
< any 小于子査询结果中的某个值
< all 小于子査询结果中的所有值
>= any 大于等于子査询结果中的某个值
>= all 大于等于子査询结果中的所有值
<= any 小于等于子査询结果中的某个值
<= all 小于等于子査询结果中的所有值
= any 等于子査询结果中的某个值
= all 等于子査询结果中的所有值(通常没有实际意义)
!= any 或 <> any 不等于子査询结果中的某个值
!= all 或 <> all 不等于子査询结果中的任何一个值
  • 本题目也可以用聚集函数来实现,代码如下:
select Sname , Sage 
	from Student
	where Sgae < 
		(
			select max(Sage)
			from Student
			where Sdept = 'CS'
		)
	and Sdept <> 'CS';

       这个结果我就不贴上来了。

[例3.59] 査询非计算机科学系中比计算机科学系所有学生年龄都小的学生姓名及年龄。


       这里我们用两种方法来写,代码如下:

select Sname , Sage 
	from Student 
	where Sage < all
	(
		select Sage 
		from Student 
		where Sdept = 'CS'
	)
and Sdept<> 'CS';

结果如下图:

在这里插入图片描述

  • 我们很容易知道:此题也可以用聚集函数来解决,代码如下:
select Sname , Sage 
	from Student where Sage < 
		(
			select min(Sage)
			from Student
			where Sdept = 'CS'
		)
and Sdept <> 'CS';

  • 显然使用聚集函数更加容易理解,并且,聚集函数实现子查询的效率相对于使用 any 或者 all 来说高些,他们的对应表如下:
= <> 或 != < <= > >=
any in -- < max <= max > min >= min
all -- not in < min <= min > max >= max
发布了12 篇原创文章 · 获赞 17 · 访问量 8472

猜你喜欢

转载自blog.csdn.net/qq_31747473/article/details/104942609