前言
EXISTS代表存在量词∃,带有EEISTS谓词的子查询不反悔任何数据,只产生逻辑真值“true”或逻辑假值“false”。
由EXISTS引出的子查询,其目标列表达式通常都用*
,因为EXISTS的子查询只返回真值假值,给出列名无实际意义。
使用到的表/数据
用到的表:
- 学生表
- 课程表
- 学生选课表
学生表:Student(Sno,Sname,Sex,Sage,Sdept)
学号Sno | 姓名Sname | 性别Sex | 年龄Sage | 所在系Sdept |
---|---|---|---|---|
201215121 | 李勇 | 男 | 20 | CS |
201215122 | 刘晨 | 女 | 20 | CS |
201215123 | 王敏 | 女 | 18 | MA |
201215125 | 张立 | 男 | 19 | IS |
课程表:Course(Cno,Cname,Cpno,Ccredit)
课程号Cno | 课程名Cname | 先行课Cpno | 学分Ccredir |
---|---|---|---|
1 | 数据库 | 5 | 4 |
2 | 数学 | 3 | |
3 | 信息系统 | 1 | 4 |
4 | 操作系统 | 6 | 3 |
5 | 数据结构 | 7 | 4 |
6 | 数据处理 | 2 | |
7 | PASCAL语言 | 5 | 4 |
学生选课表:SC(Sno,Cno,Garde)
学号Sno | 课程号Cno | 成绩Grade |
---|---|---|
201215121 | 1 | 92 |
201215121 | 2 | 85 |
201215121 | 3 | 88 |
201215122 | 2 | 90 |
201215122 | 3 | 80 |
建立表的SQL语句
/*建立一个学生表Student*/
CREATE TABLE Student
(Sno CHAR(9) PRIMARY KEY,
Sname CHAR(20) UNIQUE,
Ssex char(2),
Sage SMALLINT,
Sdept CHAR(20)
);
/*建立一个课程表 Course*/
CREATE TABLE Course
(Cno CHAR(4) PRIMARY KEY,
Cname CHAR(40) NOT NULL,
Cpno CHAR(4),
Ccredit SMALLINT
);
/*建立学生选课表SC*/
CREATE TABLE SC
(Sno CHAR(9),
Cno char(4),
Grade SMALLINT,
PRIMARY KEY(Sno,Cno),
FOREIGN key(Sno) REFERENCES Student(Sno),
FOREIGN key(Cno) REFERENCES Course(Cno)
);
插入数据:
/*插入语句*/
INSERT INTO student VALUES('201215121','李勇','男',20,'CS');
INSERT INTO student VALUES('201215122','刘晨','女',19,'CS');
INSERT INTO student VALUES('201215125','张立','男',19,'IS');
INSERT INTO student VALUES('201215123','王敏','女',18,'MA');
INSERT INTO course VALUES('1','数据库','5',4);
INSERT INTO course VALUES('2','数学',' ',2);
INSERT INTO course VALUES('3','信息系统','1',4);
INSERT INTO course VALUES('4','操作系统','6',3);
INSERT INTO course VALUES('5','数据结构','7',4);
INSERT INTO course VALUES('6','数据处理','',2);
INSERT INTO course VALUES('7','PASCAL语言','6',4);
INSERT INTO course VALUES('8','DB_Design','1',3);
INSERT INTO course VALUES('9','DB_DataDesign','8',4);
INSERT INTO sc VALUES('201215121','1',92);
INSERT INTO sc VALUES('201215121','2',85);
INSERT INTO sc VALUES('201215121','3',88);
INSERT INTO sc VALUES('201215122','2',90);
INSERT INTO sc VALUES('201215122','3',80);
例题1
问题:查询所有选修了1号课程的学生姓名。
此查询涉及的表Student和SC表。可以在Student中依次选取每个元组数据的Sno值,用此值去检查SC表。若SC中存在这样的元组,其Sno值等于此Srudent.Sno值并且Cno=1,则取此Student.Sname送入结果表。
对应逻辑的SQL语句:
SELECT Sname
FROM Student
WHERE EXISTS(
SELECT *
FROM SC
WHERE Sno=Student.Sno AND Cno='1'
);
使用EXISTS后,若内层查询结果非空,则外层的WHERE子句返回真值,否则返回假值。
运行结果:
由学生选课表表我们可以看到,选修1号课程的只有李勇一个人。所以输出结果是正确的。
例题2
问题:查询至少选修了学生201215122选修的全部课程的学生号码。
问题分析:
要求查出至少选修了学生201215122的全部课程的学生,学生201215122选修的课程包括(2数学、3信息系统),换层意思理解就是,要找出的学生是只要201215122选修的课程他都选了。
本查询可以用逻辑蕴含来表达:查询学号为X的学生,对所有的课程y,只要201215122学生选修了课程y,则x也选修y。
用p表示:“学生201215122选修了课程y”
用q表示:“学生x选修了课程y”
最终可以理解为:不存在这样的y(课程),学生201215122选修了y,而学生x没有选修。
SQL语句逻辑:
此SQL语句分三层来理解
第一层,选取学生选课表中的一条数据来,判断这一条数据符不符合条件。
第二层,筛选出201215122学生在学生选课表中的数据。
第三层,判断第一层选出的数据的学生选修的课程,是否包含第二层筛选出来的数据中的课程号。
我们通过图文来理解以下:
ok,对应的SQL语句为。
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));
运行截图:
END!