SELECT连接查询和嵌套查询

连接查询

同时涉及到两个及以上表的查询。

语句:

SELECT <列名1>[,<列名2>,...]
FROM <1>,<2>[,<3>,...]
WHERE [<表名1>.]<列名1><比较运算符>[<表名2>.]<列名2>;
--WHERE后为连接条件,其中<列名1><列名2>为连接字段

连接条件:用于连接两个表的条件。
连接字段:连接条件中的列名称。

1.等值连接与非等值连接

(1)等值连接:

类似于关系代数中的等值连接。用到的比较运算符为=。

【例3.49】查询每个学生及其选修课程的情况。

	SELECT Student.*,SC.*
	FROM Student,SC
	WHERE Student.Sno = SC.Sno;
	--同名的属性列要加表名加以限制

在这里插入图片描述连接结果与SC表中的元组个数相同。

(2)非等值:

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

这里结果的表太大了,没有剪过来。

连接,就是先做两个表的笛卡尔积,而后选择满足条件的。

等值连接和非等值连接成互补关系,Student表和SC表两者的笛卡尔积元组个数为11x8=88个,除去等值连接的8个还有80个。
在这里插入图片描述
【用SQL表示笛卡尔积】

SELECT Student.*,SC.*
FROM Student,SC;

在这里插入图片描述这里只截取了部分。
该表共有5+3=8列,11x8=88行。

(3)自然连接

类似于关系代数中的自然连接,将等值连接中的重复元组和属性去掉。

【例3.50】用自然连接完成【例3.49】
也就是去掉重复的属性列,Sno只保留一个表中的。

SELECT Student.Sno,Sname,Ssex,Sdept,Sage,Cno,Grade
--虽然只保留一个Sno,也要指明是那个表的
FROM Student,SC
WHERE Student.Sno=SC.Sno;

在这里插入图片描述
【一条SQL语句同时表示连接和选择查询】

【例3.50】查询选修2号课程并且成绩在85分以上的所有学生的姓名和学号。

题目分析:
“选修2号课程”、“成绩”——SC表
“学生姓名、学号”——Student表

SELECT Sname,Student.Sno
FROM Student,SC
WHERE Student.Sno=SC.Sno
      AND Cno='2' AND Grade > 85;
--用AND连接条件

在这里插入图片描述执行过程:
1)先对SC表进行选择,产生中间关系A
2)将中间关系A与表Student连接

2.自身连接

一个表与自己连接。
需要使用别名以示区别。

【例3.52】查询每一门课的间接先行课。

SELECT FIRST.Cno,SECOND.Cpno
FROM Course FIRST,Course SECOND
WHERE FIRST.Cpno = SECOND.Cno;

如下图所示:
在这里插入图片描述
自己与自己连接,分别看做两个表连接。

结果:
标准SQL:
在这里插入图片描述
SQL-Server显示结果:
在这里插入图片描述
emmm…最后的8 7 是我之前测试数据时添加的。
【区别】

标准SQL不要空值
SQL-Server会接受空值

3.外连接

普通连接会显示出满足条件的元组,其中某些元组因为不满足条件没有办法连接。

外连接就是将这些不满足条件,没有连接成功的元组(在关系代数中叫做 悬浮元组)也显示出来,在其属性列中补空值。

左外连接——将左边关系中所有元组显示出来
右外连接——将右边关系中所有元组显示出来

【例3.53】改写【例3.49】,查询每个学生及其选修课程的情况和未选课的学生情况。

这里要显示所有学生的情况,不论是否选课,也就是将Student关系中的元组全部列出来,需要 左外连接。

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

左外连接 —— LEFT OUTER JOIN或LEFT JOIN
右外连接 —— RIGHT OUTER JOIN或RIGHT JOIN
外连接 —— FULL OUTER JOIN或FULL JOIN

(刚开始用的LEFT OUT JOIN会显示错误,OUT错误,于是换为了OUTER,百度发现LEFT JOIN也可以。)
ON 后面加连接条件。
在这里插入图片描述单纯做连接,结果如下:
在这里插入图片描述注:
1> 这里做右外连接和连接是一样的,因为SC表中的Sno是外码,引用Student表中的Sno,根据参照完整性规则,SC.Sno要么为空,要么取自Student.Sno,所以SC表中的元组都满足连接条件。
2> 外连接因为右关系中没有连接失败的元组,所以和左外连接的结果一样。

4.多表连接

两个以上的表进行连接。

【例3.54】查询每个学生的学号、姓名、选修的课程名和成绩

“学号、姓名” —— Student
“选修课程名” —— Course
“成绩” —— SC

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

下面的表为三张表连接表
在这里插入图片描述

嵌套查询

1.有关概念

(1)查询块:一个SELECT-FROM-WHERE语句
(2)嵌套查询:将一个查询块嵌套在另一个查询块的WHERE子句或者HAVING短语的条件中的查询。(就是在条件中嵌套另一查询块)
(3)外层查询(父查询):外层的查询块
(4)内层查询(子查询):内层的查询块
(5)不相关子查询:子查询不依赖于父查询,与父查询无关。

由里向外逐层处理。先求子查询的结果,应用于父查询的结果,逐层查询。

【例3.55】查询和刘晨同系的的学生学号、姓名、系别。

①嵌套查询方法

SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept IN
           (SELECT Sdept
           FROM Student
           WHERE Sname = '刘晨');
--父查询和子查询无关

先确定刘晨所在的系别(CS),以此为条件再做选择。
在这里插入图片描述
等同于:

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

②自身连接方法

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

取两个Student表,上述语句同时完成S2表的选择和S1和S2表的连接。
先选择S2,产生名字是刘晨的中间关系,而后再将这个中间关系通过Sdept与S1表连接。

(6)相关子查询:子查询与父查询有关联。

执行过程↓
①取出外层查询的一个元组,针对这个元组计算内层查询结果,而后判断WHERE条件是否成立,成立的取出
②再取出外层的另一元组,重复上述操作,直到外层查询的元组取完。

也就是,对每一个外层查询的元组,经历一遍内层查询,计算一下结果。

【区别】
不相关子查询是对整个外层查询的所有元组,内层查询是一个定值
相关子查询对于每个外层查询的元组,内层为确定值,而对于所有是不同值

【例3.57】找出每个学生超过他选修课程平均成绩的课程号

SELECT Sno,Cno
FROM SC x
WHERE Grade >= 
          (SELECT AVG(Grade)
          FROM SC y
          WHERE y.Sno = x.Sno);

这里子查询中与父查询有关,涉及到父查询的x表。

先取出一个外层的元组(假设Sno = ‘201215121’),对于这个元组,进入内层,就是计算学号为201215121的平均成绩,然后再回到外层的条件中进行筛选,再取下一个,直至取完。

在这里插入图片描述

2.带有IN谓词的子查询

【例3.56】查询选修了课程名为信息系统的学生学号和姓名。

“选修” —— SC表
“课程名” —— Course表
“学生学号和姓名” —— Student表

SELECT Sname,Sno
FROM Student
WHERE Sno IN
          (SELECT Sno
           FROM SC
           WHERE Cno IN
                     (SELECT Cno
                      FROM Course
                      WHERE Cname = '信息系统')
           );

该查询为不相关子查询,由内往外进行。

这里注意 ; 的位置在最外层括号处,因为是英文符号不会成双成对直接打出,要注意不要遗漏括号和分号
在这里插入图片描述
用连接查询实现【例3.56】

SELECT Sname,Student.Sno
FROM Student,SC,Course
WHERE Student.Sno = SC.Sno 
      AND Course.Cno = SC.Cno
      AND Course.Cname = '信息系统';

这里的Sno要指明是哪一个表,因为三个表同时出现,与上方嵌套处有所不同。

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

比较运算符:=,!=或<>,>,<,>=,<=

当能确切知道内层查询返回单值时,可以用比较运算符。

例如上述例题中的【例3.55】,每个学生只可能在一个系学习,所以IN可以用=代替

还有上述【例3.57】也是采用了 >= 运算符作为条件

4.带有ANT(或SOME)和ALL谓词的子查询

大于ANY —— 大于MIN
小于ANY —— 小于MAX
大于ALL —— 大于MAX
小于ALL —— 小于MIN

【例3.58】查询非计算机科学系中比计算机科学系(CS)任意一个学生年龄小的学生姓名和年龄

① 比任意一个都要小 —— 比其中一个小 —— ANY

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

在这里插入图片描述下面的表为CS同学的所有年龄取值,所以非CS系的只要小于MAX 22就算满足条件

② 用聚集函数实现【例3.58】

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

【例3.59】查询非计算机科学系中比计算机科学系(CS)所有学生年龄小的学生姓名和年龄

①所有学生 —— ALL

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

在这里插入图片描述
上题中可以知道CS系别的学生年龄为19~22,小于所有,就是小于MIN 19的。

②用聚集函数

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

【总结】
这里借ppt上的表做一下总结
在这里插入图片描述

发布了10 篇原创文章 · 获赞 11 · 访问量 3628

猜你喜欢

转载自blog.csdn.net/fu_GAGA/article/details/104901745