关于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还是生效了?

EXISTS或者NOT EXISTS是把主查询的字段传到后边的查询中作为条件,返回值是TRUE或者FALSE。EXISTS TRUE,那么就是查询条件成立,结果会显示出来。NOT EXISTS TRUE,则为FALSE,查询连接条件不成立。
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)
);
View Code

                                        技术分享                技术分享     

 

/*查询至少有一门课没选的学生姓名*/
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的问题的主要内容,如果未能解决你的问题,请参考以下文章

SQL 语句中 exists和not exists的用法

oracle中in,not in和exists,not exists之间的区别

SQL语句中exists/not exists的用法分析

Exists 和Not Exists使用

oracle_not exists和not in的用法和区别

oracle中的exists 和not exists 用法详解