数据库作业8:SQL练习5 - SELECT(嵌套查询EXISTS、集合查询、基于派生表的查询)

一、带有EXISTS谓词的子查询

①EXISTS代表存在量词∃。带有EXISTS的子查询不返回任何数据,只产生逻辑真值‘true’或逻辑假值‘false’。
②使用存在量词EXISTS后,若内层查询结果非空,则外层的WHERE子句返回真值,否则返回假值。
③与EXISTS谓词相对的是NOT EXISTS谓词,使用存在量词NOT EXISTS后,若内层查询结果,则外层的WHERE子句返回真值,否则返回假值。
④由EXISTS引出的子查询,其目标列表达式通常都用*,因为带EXISTS的子查询只返回真值或假值,给出列名无实际意义。
⑤所有带IN谓词、比较运算符、ANY和ALL谓词的子查询都能用带EXISTS谓词的子查询等价替换。
在这里插入图片描述
(本例是相关子查询)

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

查询结果:在这里插入图片描述
在这里插入图片描述

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

查询结果:在这里插入图片描述
在这里插入图片描述
SQL里没有全称量词,但是可以把带有全称量词的谓词转换为等价的带有存在量词的谓词。
所以该题的意思可以转换为:查询这样的学生,没有一门课是他不选修的。

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

从而EXISTS和NOT EXISTS来实现带全称量词的查询。
在这里插入图片描述
本查询可以用逻辑蕴涵来表达:查询学号为x的学生,对所有的课程y,只要201215122学生选修了课程y,则x也选修了y。
形式化表示:用p表示谓词“学生201215122学生选修了课程y”
用q表示谓词“学生x选修了课程y”
则上述查询为:(∀y)p→q
SQL语言中没有蕴涵逻辑运算,但是可以利用谓词演算将一个逻辑蕴涵的谓词等价转换为:p→q ≡ ┐p∨q
该查询可以转换为如下形式:
(∀y)p→q≡ ┐∃y(p∧┐q)意思为:不存在这样的课程y,学生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));

二、集合查询

集合操作主要包括并操作UNION交操作INTERSECT差操作EXCEPT
在这里插入图片描述

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

查询结果:在这里插入图片描述
使用UNION将多个查询结果并起来时,系统会自动去掉重复元组。如果要保留重复元组则用UNION ALL操作符
在这里插入图片描述

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

查询结果:在这里插入图片描述
在这里插入图片描述

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

查询结果:在这里插入图片描述
(没有什么错是不能出的😁,我第一个SELECT后面写的*,第二个我就写成了Sno,然后就出错了🐷自罚三瓶养乐多👍在这里插入图片描述
在这里插入图片描述

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

查询结果:在这里插入图片描述
(注意,这个题就不能SELECT *,否则会没有查询结果,因为上一题查询的是不同属性,而这个题查询的是同一个属性的不同结果,比如这个查询时如果不只选择学号,则会造成课程号和成绩不同则没有查询结果)
在这里插入图片描述

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

查询结果:在这里插入图片描述
(也就是查询计算机科学系中年龄大于19岁的学生)


三、基于派生表的查询
子查询不仅可以出现在WHERE子句中,还可以出现在FROM子句中,这时子查询生成的临时派生表成为主查询的查询对象。

在这里插入图片描述

/*改写后的*/
SELECT Sno,Cno
FROM SC,(SELECT Sno,AVG(Grade) FROM SC GROUP BY Sno)
         AS Avg_SC(avg_sno,avg_grade)
WHERE SC.Sno=Avg_sc.avg_sno and SC.Grade>=Avg_sc.avg_grade

/*改写前的*/
SELECT Sno,Cno
FROM SC x
WHERE Grade>=(SELECT AVG(Grade)
              FROM SC y
			  WHERE y.Sno=x.Sno);

查询结果都为 :在这里插入图片描述

Emmmm,相比较我更喜欢改写前的那种(因为好写)。
改写前的意思是:这就是一个嵌套查询,先查询SC x的学生,然后在y里求了这个学生所有选修的平均成绩后,在跟该学生的各科成绩比较,然后返回符合条件的查询值。
改写后的意思是:FROM子句中子查询会生成一个新表,主查询将SC表和新生成的派生表再通过某种属性相连接。

如果子查询中没有聚集函数,派生表可以不指定属性列,子查询SELECT后面的列名为其默认属性。比如下例:
在这里插入图片描述

/*改写后的*/
SELECT Sname
FROM Student,(SELECT Sno FROM SC WHERE Cno='1')AS SC1
WHERE Student.Sno=SC1.Sno;

/*改写前的*/
SELECT Sname
FROM Student
WHERE EXISTS
      (SELECT*
       FROM SC
	   WHERE Sno=Student.Sno AND Cno='1');

查询结果都是:在这里插入图片描述

改写前的意思是:查询Student表里的学生,在查找SC表这些学生里Cno是否为1,是的话返回真值,返回该学生对应的Sname,不是的话查询下一个元组。
改写后的意思是:把SC表里Cno=1的形成一个派生表,在查询与Student表与SC表里Sno相等的,返回该学生的Sname。

通过FROM子句生成派生表时,AS关键字可以省略,但必须为派生关系指定一个别名。


SELECT总结:

SELECT语句的一般格式:

SELECT [ALL|DISTINCT] 	<目标列表达式> [别名] [ ,<目标列表达式> [别名]]FROM <表名或视图名> [别名] [ ,<表名或视图名> [别名]]|(<SELECT语句>)[AS]<别名>
[WHERE <条件表达式>] 
[GROUP BY <列名1>[HAVING<条件表达式>]] 
[ORDER BY <列名2> [ASC|DESC]];

SELECT查询:

①单表查询:选择表中的若干列;选择表中的若干元组;ORDER BY子句;聚集函数;GROUP BY子句。
②连接查询:等值与非等值连接查询;自身连接;外连接;多表连接。
③嵌套查询:带IN谓词的子查询;带有比较运算符的子查询;带有ANY或ALL谓词的子查询;带有EXISTS谓词的子查询。
④集合查询:集合操作主要包括并操作UNION交操作INTERSECT差操作EXCEPT
⑤基于派生表的查询

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章