【3.16数据库作业7】SQL练习4 - SELECT(连接查询、嵌套查询)

先看看今天学了个啥 (除了②.4)
在这里插入图片描述
①:连接查询----中级
1.等值与非等值连接查询
2.自身连接
3.外连接
4.多表连接

②:嵌套查询----高级
相关子查询
不相关子查询
1.带有IN谓词的子查询
2.带有比较运算符的子查询
3.带有ANY(SOME)或ALL谓词的子查询

4.带有EXISTS谓词的子查询(重点、难点)

①:连接查询----中级

1.等值与非等值连接查询
连接查询:同时涉及两个以上的表的查询
连接条件:用来连接两个表的条件

[<表名1>.]<列名1>  <比较运算符>  [<表名2>.]<列名2>
 Student.Sno           =             SC.Sno

例:Student.Sno = SC.Sno
连接字段:连接条件中的列名称
如:Sno为上面例子中的连接字段
注意:连接字段类型必须是可比的(即类型必须相同),但名字不必相同
[例 3.49] 查询每个学生及其选修课程的情况-----等值连接

SELECT  Student.*, SC.*
FROM     Student, SC
WHERE  Student.Sno = SC.Sno;

<=>

 SELECT  *
 FROM    Student,SC
 WHERE   Student.Sno = SC.Sno;

在这里插入图片描述
若将条件(WHERE Student.Sno = SC.Sno;)去掉则结果为

55个元组
我的SC表有5个元组Student表有11个元组11*5=55
即为SC与Student表做笛卡尔积
而我们加上条件之后得出的结果只是这个的一部分

[例 3.50] 对[例 3.49]用自然连接完成。

 SELECT  Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
 FROM    Student,SC
 WHERE   Student.Sno = SC.Sno;

在这里插入图片描述
[例 3.51 ]查询选修2号课程且成绩在90分以上的所有学生的学号和姓名。

SELECT Student.Sno,Sname
FROM Student, SC
WHERE  Student.Sno=SC.Sno  AND  SC.Cno='2' AND SC.Grade>86;

在这里插入图片描述
一条SQL语句可以同时完成连接和查询操作。先从Student中和SC表中满足连接条件的元组进行连接后,再在SC中选择出Cno='2’并且Grade>90的元组作为条件筛选得到最终的结果关系

这里需要注意的是因为Sno在两个表中都有,所以需要注明一下(Student.Sno)/(Sname.Sno)都可,而唯一的属性例如Grade只存在于SC中,所以无需标注表名
例如

SELECT SC.Sno,Sname
FROM Student, SC
WHERE  Student.Sno=SC.Sno  AND  Cno='5' AND Grade>50;

2.自身连接
一个表与其自己进行连接需要给表起别名以示区别,所有属性名都是同名属性,因此必须使用“别名”
[例 3.52]查询每一门课的间接先修课(即先修课的先修课)

SELECT  FIRST_TABLE.Cno, SECOND_TABLE.Cpno
FROM    Course  FIRST_TABLE, Course  SECOND_TABLE
WHERE   FIRST_TABLE.Cpno = SECOND_TABLE.Cno;

我们可以将一张表看成两张相同的表,再进行WHERE条件查询
在这里插入图片描述
在这里插入图片描述
标准SQL不显示空值,即无3、5行

3.外连接

外连接与普通连接的区别:
普通连接操作只输出满足连接条件的元组
外连接操作以指定表为连接主体,将主体表中不满足连接条件的元组一并输出

外连接就好比说我们在录入成绩的时候不能把那些成绩为NULL的学生去掉

左外连接
列出左边关系中所有的元组
右外连接
列出右边关系中所有的元组
[例 3. 53] 改写[例 3.49]

SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
FROM  Student  LEFT OUTER JOIN SC ON  (Student.Sno=SC.Sno);

对比一下【3.49】和【3.53】
在这里插入图片描述
可以看到在【3.49】中只显示选课的同学,而【3.53】左外连接后会显示所有学生,即LEFT左边Student中所有的元组

SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
FROM  Student  inner JOIN SC ON  (Student.Sno=SC.Sno);

[例3.54]查询每个学生的学号、姓名、选修的课程名及成绩-------4.多表连接:两个以上的表进行连接

SELECT Student.Sno, Sname, Cname, Grade
FROM Student, SC, Course
WHERE Student.Sno = SC.Sno AND SC.Cno = Course.Cno;
SELECT *
FROM Student, SC, Course
WHERE Student.Sno = SC.Sno AND SC.Cno = Course.Cno;

分清哪个属性是唯一存在于某个表中的 比如选修的课程名唯一来自Course 成绩唯一来自SC
在这里插入图片描述

②:嵌套查询----高级

一个SELECT-FROM-WHERE语句称为一个查询块
将一个查询块嵌套在另一个查询块的WHERE子句或HAVING短语的条件中的查询

SELECT *	                           /*外层查询/父查询*/
FROM Student
WHERE Sno IN
	(SELECT Sno        /*内层查询/子查询*/
	FROM SC
	WHERE Cno= '2');

SQL语言允许多层嵌套查询:
即一个子查询中还可以嵌套其他子查询
子查询的限制:不能使用ORDER BY子句

这里需要注意关于子查询的两类查询

①:不相关子查询:子查询的查询条件不依赖于父查询
由里向外 逐层处理。即每个子查询在上一级查询处理之前求解,子查询的结果用于建立其父查询的查找条件。

②:相关子查询:子查询的查询条件依赖于父查询
首先取外层查询中表的第一个元组,根据它与内层查询相关的属性值处理内层查询,若WHERE子句返回值为真,则取此元组放入结果表,然后再取外层表的下一个元组。重复这一过程,直至外层表全部检查完为止

所以子查询是否依赖于父查询是相关与否的判断标准。

1.带有比较运算符的子查询 (>,<,=,>=,<=,!=或< >)
[例 3.55] 查询与“刘晨”在同一个系学习的学生。
方案1:两步走
① 先确定“刘晨”所在系名

SELECT  Sdept  
FROM    Student                            
WHERE   Sname= '刘晨';

得到结果为: CS
②再查找所有在CS系学习的学生。

SELECT   Sno, Sname, Sdept     
FROM      Student                 
WHERE   Sdept= 'CS'; 

方案2:一步即达(将①的查询结果嵌套在②的查询条件中)
在这里插入图片描述

SELECT Sno, Sname, Sdept
FROM Student
WHERE Sdept  IN
	(SELECT Sdept
	FROM Student
	WHERE Sname= '刘晨');

2.因为一个学生只可能在一个系学习,所以这里可以用=代替IN,但如果学生和系是一对多的关系,则不可代替
此时报错:子查询返回的值不止一个。当子查询跟随在 =、!=、<、<=、>、>= 之后,或子查询用作表达式时,这种情况是不允许的。

方案3:用自身连接完成

SELECT  S1.Sno, S1.Sname,S1.Sdept
FROM    Student S1,Student S2
WHERE   S1.Sdept = S2.Sdept  AND  S2.Sname = '刘晨';

这个感觉也很像两步走①:先把同系的绑在一起②:再把和刘晨同系的绑起来
在这里插入图片描述
在这里插入图片描述
做一个对比吧
方案一逻辑很清晰先做这一步,后做那一步
方案二语句清晰,其实也还好;
方案三是利用别名做出来的 不过感觉在c中函数原型还需要提前声明 在DB中别名直接写出 后面再FROM中注明就好了(我这是个什么联想hhh )
[例 3.56]查询选修了课程名为“信息系统”的学生学号和姓名

不相关子查询

--不相关子查询
SELECT Sno,Sname
FROM   Student
WHERE  Sno  IN
		    (SELECT Sno
   			 FROM   SC
     		 WHERE  Cno IN
					   (SELECT Cno
                        FROM   Course
                        WHERE  Cname= '信息系统'
		               )
              );

分了三层,1-2-3 逐层向外
①:首先在Course关系中找出“信息系统”的课程号,为3号
② 然后在SC关系中找出选修了3号课程的学生学号
③ 最后在Student关系中取出Sno和Sname
在这里插入图片描述
我在敲dangdangdang
连接查询实现

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
		);

子查询执行中用到了父查询的值(x)
每当从父查询中取出SC的一个元组x,便将元组x的Sno值传送给子查询。

SELECT AVG(Grade)
FROM   SC y
WHERE  y.Sno='201215121';

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

SELECT Sno,Cno
FROM   SC x
WHERE  Grade >=88; 

这个过程就是先求平均值再分别与各科成绩作对比

在这里插入图片描述
3.带有ANY(SOME)或ALL谓词的子查询
这次作业最后一部分了 坚持住
使用ANY或ALL谓词时必须同时使用比较运算

谓词 含义
>ANY 大于子查询结果中的某个值(大于最小值)
>ALL 大于子查询结果中的所有值(大于最大值)
<ANY 小于子查询结果中的某个值(小于最大值)
< ALL 小于子查询结果中的所有值(小于最小值)
>=ANY 大于等于子查询结果中的某个值(大于等于最小值)
>= ALL 大于等于子查询结果中的所有值(大于等于最大值)

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

SELECT Sname,Sage
FROM   Student
WHERE  Sage < ANY 
           (SELECT  Sage
			FROM    Student
			WHERE   Sdept= 'CS')
       AND Sdept <> 'CS';           /*父查询块中的条件 */

1、首先处理子查询,找出CS系中所有学生的年龄,构成一个集合
2、然后处理父查询,【<ANY (子查询结果)】即为找所有年龄小于1中集合中年龄最大的学生,并且不是CS系的学生

或用聚集函数

SELECT Sname,Sage
FROM   Student
WHERE  Sage < 
		(SELECT MAX(Sage)
		 FROM   Student
		 WHERE  Sdept= 'CS')
       AND Sdept <> 'CS';

1、首先处理子查询,找出CS系中所有学生的年龄的最大值
2、然后处理父查询,找所有不是CS系且年龄小于20的学生
在这里插入图片描述
一定要自己敲一下
一定要自己敲一下
一定要自己敲一下

记清一些概念,相关子查询/不相关子查询
注意点:IN和=在什么情况下相等
在这里插入图片描述

再复习一下前天所学

①:连接查询----中级
1.等值与非等值连接查询
2.自身连接
3.外连接
4.多表连接

②:嵌套查询----高级
相关子查询
不相关子查询
1.带有IN谓词的子查询
2.带有比较运算符的子查询
3.带有ANY(SOME)或ALL谓词的子查询

ok 感谢观看
在这里插入图片描述

发布了14 篇原创文章 · 获赞 13 · 访问量 1980

猜你喜欢

转载自blog.csdn.net/summer__kkkk/article/details/104924907