【数据库系统设计】关系数据库标准语言SQL(2)

全部的笔记戳这里,虽然实际项目中用不到这么多 sql 的知识点,但是记录一下,了解一下也OK。
【数据库系统设计】关系数据库标准语言SQL(1)
【数据库系统设计】关系数据库标准语言SQL(3)

数据查询(连接查询)

等值连接 =

Ex:查询每个学生及其选修课程的情况。(等值连接)

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

在这里插入图片描述

自然连接

Ex:查询每个学生及其选修课程的情况。(自然连接)
采用在SELECT中去掉重复字段的方式实施

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

在这里插入图片描述

Ex:查询选修2号课程且成绩在70分以上的所有学生的学号和姓名。

SELECT SC.Sno, Student.Sname
FROM Student, SC
WHERE Student.Sno = SC.Sno /*连接谓词*/
AND SC.Grade >= 70 /*选择谓词*/

在这里插入图片描述

自身连接

自身连接:一个表与其自己进行连接,是一种特殊的连接

  • 需要给表起别名以示区别
  • 由于所有属性名都是同名属性,因此必须使用别名前缀

Ex:查询每一门课的直接先修课的名称。

SELECT First.Cname, Second.Cname
/*FROM子句中,可以为表或视图取一别名,这别名只在本句中有效*/ 
FROM Course First, Course SECOND
WHERE FIRST.Cpno = SECOND.Cno;

在这里插入图片描述

外连接 LEFR/RIGHT JOIN ... ON

外连接与普通连接的区别

  • 普通连接操作只输出满足连接条件的元组
  • 外连接操作以指定表为连接主体,将主体表中不满足连接条件的元组一并输出
  • 左外连接LEFT JOIN
    • 列出左边关系中所有的元组
  • 右外连接RIGHT JOIN
    • 列出右边关系中所有的元组
select <目标列表达式> [ into 表名 ]
from 表名1 [ inner | right | left | full ] [ outer ] 
join 表名2 on 条件

inner join: 内连接,显示符合 on 指定连接条件的记录
left [outer] join:左外连接,连接结果中包括左表(表名1)中的所有行,而不仅仅是连接列所匹配的行。如果表名1的某行在表名2中没有匹配行,则在该行新增加的属性上填空值。
right (outer) join:右外连接,返回右表(表名2)的所有行。如果右表的某行在左表中没有匹配行,则在新增加的属性上填空值。
full (outer) join: 完全外连接,返回左表和右表中的所有行。当某行在另一个表中没有匹配行时,则另一个表新增加的属性上填空值。

Ex:查询每个学生及其选修课程的情况(外连接)。

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

在这里插入图片描述

多表连接

多表连接:两个以上的表进行连接
Ex:查询每个学生的学号、姓名、选修的课程名及成绩。

SELECT Student.Sno, Sname, Cname, Grade
FROM Student, SC, Course /*多表连接*/
WHERE Student.Sno = SC.Sno AND SC.Cno = Course.Cno;

在这里插入图片描述

数据查询(嵌套查询 )

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

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

上层的查询块称为外层查询父查询
下层查询块称为内层查询子查询
SQL语言允许多层嵌套查询
子查询的限制:不能使用ORDER BY子句

不相关子查询 :子查询的查询条件不依赖于父查询

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

相关子查询:子查询的查询条件依赖于父查询

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

带有IN谓词的子查询

Ex:查询与“刘晨”在同一个系学习的学生。(不相关子查询
① 确定“刘晨”所在系名

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='刘晨');

在这里插入图片描述

Ex:查询与“刘晨”在同一个系学习的学生。 (自连接

SELECT S1.Sno, S1.Sname,S1.Sdept
FROM Student S1, Student S2 
WHERE S1.Sdept = S2.Sdept 
AND  S2.Sname = '刘晨'; /*这里不能写S1.Sname*/

Ex:查询选修了课程名为“信息系统”的学生学号和姓名。

SELECT Sno, Sname/*3最后在Student关系中取出Sno和Sname */
FROM Student 
WHERE Sno IN 
	(SELECT Sno FROM/*2然后在SC关系中找出选修了3号课程的学生学号*/    
	SC WHERE Cno IN
		(SELECT Cno/*1首先在Course关系中找出“信息系统”的课程号,为3号*/             
		FROM Course           
		WHERE Cname= '信息系统' 
		)
	);

Ex:查询选修了课程名为“信息系统”的学生学号和姓名。(连接查询

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

带有比较运算符的子查询

当能确切知道内层查询返回单值时,可用比较运算符(><=>=<=!=<>)。

Ex:查询与“刘晨”在同一个系学习的学生。

SELECT Sno,Sname,Sdept 
FROM Student 
WHERE Sdept = /*由于一个学生只可能在一个系学习 , 用=代替*/
	(SELECT Sdept
	FROM Student
	WHERE Sname = '刘晨'); 

Ex:找出每个学生超过他选修课程平均成绩的课程号。( 相关子查询

SELECT Sno, Cno
FROM SC x 
WHERE Grade >= (SELECT AVG(Grade)/*相关子查询*/
				FROM  SC y 
				WHERE y.Sno = x.Sno);  

在这里插入图片描述
可能的执行过程:
(1) 从外层查询中取出 SC 的一个元组 x,将元组 x 的 Sno 值(201215121)传送给内层查询。

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

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

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

(3)执行该查询,得到结果:201215121, 1

然后外层查询取出下一个元组重复做上述(1)(2)(3)步骤,直到外层的 SC 元组全部处理完毕。
得到结果:

(201215121,1)
(201215122,2) 

带有ANYALL谓词的子查询

使用ANYALL谓词时必须同时使用比较运算
语义为:

  • >ANY:大于子查询结果中的某个值
  • >ALL:大于子查询结果中的所有值
  • < ANY:小于子查询结果中的某个值
  • < ALL:小于子查询结果中的所有值
  • >= ANY:大于等于子查询结果中的某个值
  • >= ALL:大于等于子查询结果中的所有值

Ex:查询非计算机科学系中比计算机科学系任意一个学生年龄小的学生姓名和年龄(ANY实现)

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

在这里插入图片描述
执行过程:
(1) 首先处理子查询,找出CS系中所有学生的年龄,构成一个集合(20,19)
(2) 处理父查询,找所有不是CS系且年龄小于 20 或 19 的学生

Ex:查询非计算机科学系中比计算机科学系任意一个学生年龄小的学生姓名和年龄(聚集函数

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

Ex:查询非计算机科学系中比计算机科学系所有学生年龄都小的学生姓名及年龄。
方法一:ALL谓词

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(或SOME),ALL谓词与聚集函数IN谓词的等价转换关系
在这里插入图片描述

带有EXISTS谓词的子查询

EXISTS谓词

  • 存在量词 \exists
  • 带有EXISTS谓词的子查询不返回任何数据,只产生逻辑真值true或逻辑假值false
    • 若内层查询结果非空,则外层的WHERE子句返回真值
    • 若内层查询结果为空,则外层的WHERE子句返回假值
  • EXISTS引出的子查询,其目标列表达式通常都用 * ,因为带EXISTS的子查询只返回真值或假值,给出列名无实际意义。

NOT EXISTS谓词

  • 若内层查询结果非空,则外层的WHERE子句返回假值
  • 若内层查询结果为空,则外层的WHERE子句返回真值

Ex:查询所有选修了1号课程的学生姓名。
方法一:EXISTS谓词
思路分析:
本查询涉及 Student 和 SC 关系
在 Student 中依次取每个元组的 Sno 值,用此值去检查 SC 表
若 SC 中存在这样的元组,其 Sno 值等于此 Student.Sno 值,并且其 Cno= ‘1’,则取此 Student.Sname 送入结果表

SELECT Sno, Sname
FROM Student
WHERE EXISTS
	(SELECT *
	FROM SC
	WHERE SC.Sno = Student.Sno AND SC.Cno= '1');

方法二:连接查询

Select Sno, Sname
From Student, SC
Where Student.Sno=SC.Sno and Cno='1';

方法三:IN 嵌套查询

Select Sno, Sname 
From Student 
Where Sno IN
(Select Sno From SC Where Cno ='1');
Select Sno, Sname 
From Student 
Where '1' IN
(Select Cno From SC Where Sno = Student.Sno);

Ex:查询没有选修1号课程的学生姓名。
在这里插入图片描述
无法使用连接查询完成。

SELECT Sname
FROM Student
WHERE NOT EXISTS
		(SELECT *
		FROM SC
		WHERE Sno = Student.Sno AND Cno='1');

Ex:查询选修了全部课程的学生姓名。
在这里插入图片描述

SELECT Sname
FROM Student
WHERE NOT EXISTS
	(SELECT *
	FROM Course
	WHERE NOT EXISTS
		(SELECT *
		FROM SC
		WHERE Sno= Student.Sno
		AND Cno= Course.Cno));

数据查询(集合查询)

集合操作的种类

  • 并操作UNION
  • 交操作INTERSECT
  • 差操作EXCEPT

参加集合操作的各查询结果的列数必须相同;
对应项的数据类型也必须相同。

UNION:将多个查询结果合并起来时,系统自动去掉重复元组
UNION ALL:将多个查询结果合并起来时,保留重复元组

Ex:查询计算机科学系的学生及年龄不大于19岁的学生。

SELECT *
FROM Student	
WHERE Sdept='CS'
UNION
SELECT *
FROM Student
WHERE Sage<=19;

Ex:查询选修了课程1或者选修了课程2的学生。

SELECT Sno	
FROM SC
WHERE Cno='1'
UNION
SELECT Sno
FROM SC
WHERE Cno= '2';

Ex:查询计算机科学系的学生与年龄不大于19岁的学生的交集。
方法一:
mysql中会报错,原因是Mysql不支持INTERSECT交集操作

SELECT *
FROM Student
WHERE Sdept='CS'
INTERSECT
SELECT *
FROM Student
WHERE Sage<=19;

方法二:实际上就是查询计算机科学系中年龄不大 于19岁的学生。

SELECT *
FROM Student
WHERE Sdept= 'CS' AND Sage<=19;

Ex:查询既选修了课程1又选修了课程2的学生。
方法一:
mysql中会报错,原因是Mysql不支持INTERSECT交集操作

SELECT Sno
FROM SC
WHERE Cno='1'
INTERSECT
SELECT Sno
FROM SC
WHERE Cno='2';

方法二:

SELECT Sno
FROM SC
WHERE Cno='1' 
AND Sno IN
			(SELECT Sno
			FROM SC
			WHERE Cno='2');

方法三:自连接

Select X.Sno
From SC as X, SC as Y
Where X.Sno=Y.Sno
AND X.Cno='1'
AND Y.Cno='2';

Ex:查询计算机科学系的学生与年龄不大于19岁的学生的差集。
方法一:
mysql中会报错,原因是Mysql不支持EXCEPT差集操作

SELECT *
FROM Student
WHERE Sdept='CS'
EXCEPT
SELECT *
FROM Student
WHERE Sage <=19;

方法二:
实际上是查询计算机科学系中年龄大于19岁的学生。

SELECT *
FROM Student
WHERE Sdept= 'CS' AND Sage>19;

基于派生表的查询

子查询不仅可以出现在WHERE子句中,还可以出现在FROM子句中,这时子查询生成的临时派生表(Derived Table)成为主查询的查询对象

Ex:找出每个学生超过他自己选修课程平均成绩的课程号 ,可改写为:

SELECT Sno, Cno
FROM SC, (SELECT Sno avg_sno, Avg(Grade) avg_grade
					FROM SC
					GROUP BY Sno) AS Avg_sc
WHERE SC.Sno = Avg_sc.avg_sno
and SC.Grade >= Avg_sc.avg_grade;

如果子查询中没有聚集函数,派生表可以不指定属性列,子查询SELECT子句后面的列名为其缺省属性。

Ex:查询所有选修了1号课程的学生姓名,可以用如下查询完成:

SELECT Sname
FROM Student,
		(SELECT Sno FROM SC WHERE Cno='1') AS SC1
WHERE Student.Sno=SC1.Sno;

课后作业

学了全部课程的学生的姓名,用分组语句来完成:

SELECT Sname
FROM student
WHERE Sno IN 
		(
		SELECT Sno
		FROM SC
		GROUP BY Sno 
		HAVING COUNT(*) = /*学生选课数 = 总课程数*/
					(SELECT COUNT(*) FROM course) /*7*/	
		);
发布了170 篇原创文章 · 获赞 47 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_43734095/article/details/104905100
今日推荐