关于SQL语句中exists与not exists的问题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于SQL语句中exists与not exists的问题相关的知识,希望对你有一定的参考价值。
course表如下:
课程代号 课程名称
K01 奥运会主题曲
K02 喜爱的专辑
K03 VB技术大全
K04 经典歌曲
K05 个人单曲
K06 数据结构
K07 最受欢迎的歌曲
grade表如下:
学号 课程代号
B003 k03
B005 K02
B003 K05
B004 K04
B002 K02
B001 K01
B001 K06
现用SQL语句(1)查询:
select * from course where not exists(select * from grade where grade.课程代号=course.课程代号)
得到结果为:
K07 最受欢迎的歌曲
问题是:not exists的定义是子查询无返回值时where子句生效,但是为什么此例中的子查询有返回值,not exists还是生效了?
select * from course where not exists(select * from grade where grade.课程代号=course.课程代号)
这个语句,是查询course表中课程代号在grade中没有出现的数据。
看看grade表,课程编号有K01到K06,而COURSE表,有K01到K07,那么K07在GRADE表是不存在的,那么,是符合条件的。
同样select * from course where exists(select * from grade where grade.课程代号=course.课程代号)
则是查询COURSE的记录条件为编号在GRADE中存在。那么很明显,结果是K01到K06的数据。
另外,EXISTS和NOT EXISTS的作用可以用IN或NOT IN实现,但是,效率要高。
因为EXISTS和NOT EXISTS返回的结果是TRUE或者FALSE,那么则在子查询中,遇到第一个符合条件的结果,就会退出查询,而不会进行全表的检索。而NOT IN或者IN,要把子查询中的SELECT字句全部查询出来才行。 参考技术A 翻译过来不就是: 查询在B表中不存在的A表数据.这不就好理解了 参考技术B
IN
确定给定的值是否与子查询或列表中的值相匹配。
EXISTS
指定一个子查询,检测行的存在。
比较使用 EXISTS 和 IN 的查询
这个例子比较了两个语义类似的查询。第一个查询使用 EXISTS 而第二个查询使用 IN。注意两个查询返回相同的信息。
USE pubs
GO
SELECT DISTINCT pub_name
FROM publishers
WHERE EXISTS
(SELECT *
FROM titles
WHERE pub_id = publishers.pub_id
AND type = 'business')
GO
-- Or, using the IN clause:
USE pubs
GO
SELECT distinct pub_name
FROM publishers
WHERE pub_id IN
(SELECT pub_id
FROM titles
WHERE type = 'business')
GO
下面是任一查询的结果集:
pub_name
----------------------------------------
Algodata Infosystems
New Moon Books
(2 row(s) affected)
SQL 中 EXISTS 与 NOT EXISTS
带有 EXISTS 操作符的子查询不返回任何数据,只产生逻辑真值 ‘true‘ 或逻辑假值 ‘false‘。带有 EXISTS 操作符的子查询都是相关子查询。
相关子查询:子查询的条件依赖父查询。
EXISTS:如果内层查询结果非空,则外层 WHERE 子句返回真值,输出外层查询结果。
NOT EXISTS:如果内层查询结果为空,则外层 WHERE 子句返回真值,输出外层查询结果。
样例表
CREATE TABLE Student (Sno CHAR(9) PRIMARY KEY, --学号 Sname CHAR(20) UNIQUE, --姓名 ); create table SC (sno char(9), --学号 cno char(4), --课程号 primary key (sno,cno), foreign key (sno) references student(sno) );
/*查询至少有一门课没选的学生姓名*/ SELECT sname FROM Student WHERE EXISTS (SELECT * FROM Course WHERE NOT EXISTS(SELECT * FROM SC WHERE Sno=Student.Sno AND Cno=Course.Cno)); -- 外层要有查询结果 中层查询结果要为非空 内层查询结果要为空 = 至少有一门课没选 /*查询所有课都没选的学生姓名*/ SELECT sname FROM Student WHERE NOT EXISTS (SELECT * FROM Course WHERE EXISTS (SELECT * FROM SC WHERE Sno=Student.Sno AND Cno=Course.Cno)); --外层要有查询结果 中层查询结果要为空 内层查询结果要为空 = 所有的课都没选 /*查询至少选了一门课的学生姓名*/ SELECT sname FROM Student WHERE EXISTS (SELECT * FROM Course WHERE EXISTS (SELECT * FROM SC WHERE Sno=Student.Sno AND Cno=Course.Cno)); --外层要有查询结果 中层查询结果要为非空 内层查询结果要为非空 = 选了至少一门课 /*查询选了所有课的学生姓名*/ SELECT sname FROM Student WHERE NOT EXISTS (SELECT * FROM Course WHERE NOT EXISTS(SELECT * FROM SC WHERE Sno=Student.Sno AND Cno=Course.Cno)); --外层要有查询结果 中层查询结果要为空 内层查询结果要为非空 = 选了所有的课 /*用 GROUP BY */ SELECT sname FROM Student LEFT JOIN SC ON Student.Sno=SC.sno GROUP BY Sname HAVING COUNT(cno)<= (SELECT COUNT(cno) FROM Course)-1; SELECT sname FROM Student LEFT JOIN SC ON Student.Sno=SC.sno GROUP BY Sname HAVING COUNT(cno)= 0; SELECT sname FROM Student LEFT JOIN SC ON Student.Sno=SC.sno GROUP BY Sname HAVING COUNT(cno)>= 1; SELECT sname FROM Student LEFT JOIN SC ON Student.Sno=SC.sno GROUP BY Sname HAVING COUNT(cno)= (SELECT COUNT(cno) FROM Course);
/*查询至少选修了学生 201215122 选修的全部课程*/ SELECT DISTINCT sno FROM SC x WHERE NOT EXISTS (SELECT * FROM SC Y WHERE Y.sno=201215122 AND NOT EXISTS(SELECT * FROM SC Z WHERE Z.sno=X.sno AND Z.cno=Y.cno)); --外层要有查询结果 中层查询结果要为空 内层查询结果要为非空 = 至少选修了201215122 选修的全部课程 SELECT cno INTO copy FROM SC WHERE sno=201215122; --复制 201215122 选的课号到 copy 表 SELECT DISTINCT sno FROM copy LEFT OUTER JOIN SC ON SC.cno=copy.cno --以 copy 表为全部行 GROUP BY sno HAVING COUNT(SC.cno)= (SELECT COUNT(cno) --排序只选了 copy 表中的一门或几门课的 sno FROM copy);
以上是关于关于SQL语句中exists与not exists的问题的主要内容,如果未能解决你的问题,请参考以下文章
oracle中in,not in和exists,not exists之间的区别