SQL 子查询 EXISTS 和 NOT EXISTS
MySQL EXISTS 和 NOT EXISTS 子查询语法如下:
SELECT … FROM table WHERE EXISTS (subquery)
该语法可以理解为:将主查询的数据,放到子查询中做条件验证,根据验证结果(TRUE 或 FALSE)来决定主查询的数据结果是否得以保留。
exists对外表用loop逐条查询,每次查询都会查看exists的条件语句,当 exists里的条件语句能够返回记录行时(无论记录行是的多少,只要能返回),条件就为真,返回当前loop到的这条记录,反之如果exists里的条 件语句不能返回记录行,则当前loop到的这条记录被丢弃,exists的条件就像一个bool条件,当能返回结果集则为true,不能返回结果集则为 false
MySQL EXISTS 子查询实例
下面以实际的例子来理解 EXISTS 子查询。下面是原始的数据表:
article 文章表:
| aid | title | content | uid |
|---|---|---|---|
| 1 | 文章1 | 文章1正文内容… | 1 |
| 2 | 文章2 | 文章2正文内容… | 1 |
| 3 | 文章3 | 文章3正文内容… | 2 |
| 4 | 文章4 | 文章4正文内容… | 4 |
user 用户表:
| uid | title | content |
|---|---|---|
| 1 | admin | admin@5idev.com |
| 2 | 小明 | xiao@163.com |
| 3 | Jack | jack@gmail.com |
我们要查出 article 表中的数据,但要求 uid 必须在 user 表中存在。SQL 语句如下:
SELECT * FROM article WHERE EXISTS (SELECT * FROM user WHERE article.uid = user.uid)
返回查询结果如下:
| aid | title | content | uid |
|---|---|---|---|
| 1 | 文章1 | 文章1正文内容… | 1 |
| 2 | 文章2 | 文章2正文内容… | 1 |
| 3 | 文章3 | 文章3正文内容… | 2 |
从语句执行结果可以看出,article 表中第 4 条记录没有被保留,原因就是该条记录的数据在子查询中返回的结果是 FALSE 。
当上面的 SQL 使用 NOT EXISTS 时,查询的结果就是 article 表中 uid 不存在于 user 表中的数据记录。
下面来三张表的实例
我们先介绍下使用的3个数据表:
student数据表:
| sno 学号 | sname | ssex | sage |
|---|---|---|---|
| 20161181 | Altair | 男 | 20 |
| 20161182 | Desmond | 男 | 18 |
| 20161183 | Ezio | 男 | 22 |
| 20161184 | Christina | 女 | 19 |
course数据表:
| cno 课程编号 | cname 课程名 |
|---|---|
| 1 | C语言 |
| 2 | 数据结构 |
| 3 | 信号与系统 |
| 4 | 模拟电子技术 |
| 5 | 高数 |
sc数据表:
| sno 学号 | cno 课程编号 | grade 成绩 |
|---|---|---|
| 20161181 | 1 | 99 |
| 20161182 | 2 | 98 |
| 20161181 | 2 | 97 |
| 20161181 | 3 | 95 |
| 20161184 | 3 | 92 |
| 20161181 | 4 | 90 |
| 20161181 | 5 | 88 |
| 20161183 | 5 | 58 |
EXISTS
EXISTS代表存在量词∃。带有EXISTS谓词的子查询不返回任何数据,只产生逻辑真值“true”或者逻辑假值“false”。
一个例子1.1:
要求:查询选修了课程”信号与系统“的同学
SELECT s.Sname FROM student s
WHERE EXISTS
(SELECT * FROM sc, course c WHERE sc.sno = s.sno AND sc.cno = c.cno AND c.cname = '信号与系统')
使用存在量词EXISTS后,若内层查询结果为非空,则外层的WHERE子句返回值为真,否则返回值为假。
在本例中,首先分析最内层的语句:
SELECT * FROM sc, course c WHERE sc.sno = s.sno AND sc.cno = c.cno AND c.cname = '信号与系统'
本例中的子查询的查询条件依赖于外层父查询的某个属性值(本例中的是Student的Sno值),这个相关子查询的处理过程是:
首先取外层查询中(student)表的第一个元组,根据它与内层查询相关的属性值(Sno值)处理内层查询,若外层的WHERE返回为真,则取外层查询中该元组的Sname放入结果表;
然后再取(student)表的下一组,重复这一过程,直至外层(Student)表全部检查完毕。
查询结果表:
| Sname |
|---|
| Altair |
| Christina |
NOT EXISTS
与EXISTS谓词相对的是NOT EXISTS谓词。使用存在量词NOT EXISTS后,若对应查询结果为空,则外层的WHERE子语句返回值为真值,否则返回假值。
例子2.1:
要求:查询没有选修课程”信号与系统“的同学
SELECT s.Sname FROM student s
WHERE NOT EXISTS
(SELECT * FROM sc, course c WHERE sc.sno = s.sno AND sc.cno = c.cno AND c.cname = '信号与系统')
使用NOT EXISTS之后,若内层查询结果为非空,则对应的NOT EXISTS不成立,所以对应的WHERE语句也不成立。
在例子1.1中李勇同学对应的记录符合内层的select语句的,所以返回该记录数据,但是对应的NOT EXISTS不成立,WHERE语句也不成立,表示这不是我们要查询的数据。
查询结果表:
| Sname |
|---|
| Desmond |
| Ezio |
例子2.2(这是一个用NOT EXISTS表示全称量词的例子):
要求:查询选修了全部课程的学生姓名。
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)
);
这个算是一个比较复杂的sql语句了,两个EXISTS和三个WHERE。
这个sql语句可以分为3层,最外层语句,最内层语句,中间层语句。
我们很关心最外层语句,因为结果表中的数据都是最外层的查询的表中的数据,我们更关心最内层的数据,因为最内层的数据包含了全部的判断语句,决定了student表中的那一条记录是我们查询的记录。
我们由内而外进行分析:
最外层的student表中的第一条记录是Altair同学对应的记录,然后中间层的course表的第一条记录是数据库对应的记录,然后对该数据进行判断(最内层的WHERE语句),结果返回真,则内层的NOT EXISTS为假,
然后继续对course表中的下一条记录进行判断,返现NOT EXISTS的值也为假,直到遍历完course表中的所有的数据,内层的NOT EXISTS的值一直都是假,所以中间层的WHERE语句的值也一直都是假。
对应student的Altair记录,course表中的所有的记录对应的中间层的返回值为假,所以最外层的NOT EXISTS对应的值为真,最外层的WHERE的值也为真,则Altair对应的记录符合查询条件,装入结果表中。
然后继续对student表中的下一条记录进行判断,直达student表中的所有数据都遍历完毕。
下面是我自己对这段sql的解读:
先取一条student记录,进入中层,再取一条course的记录,进入内层,此时student的记录和course的记录,作为内层判断的条件,比如此时我取的第一条记录是Altair,那么我里面的Sql就可以写成
SELECT * FROM Course WHERE NOT EXISTS
(SELECT * FROM SC WHERE Sno = '' AND Cno=Course.Cno)
)
此处 sno 20161181即Altair的学号,这条sql的意思是选出没有被Altair选择的课程,如果不存在,则返回false,再跟最外层的NOT EXISTS关联,负负得正。每一条循环的意思就是指,筛选出的每一个学生都不存在没有被他选取的那门课,即选了所有课。
最终查询结果:
| Sname |
|---|
| Altair |
转:https://blog.csdn.net/qq_27571221/article/details/53090467
SQL 子查询 EXISTS 和 NOT EXISTS的更多相关文章
- sql子查询 嵌套SELECT语句
嵌套SELECT语句也叫子查询,一个 SELECT 语句的查询结果能够作为另一个语句的输入值.子查询不但能够出现在Where子句中,也能够出现在from子句中,作为一个临时表使用,也能够出现在sele ...
- sql子查询
一.子查询入门: 1.单值子查询: 单值子查询的唯一限制:子查询的返回值必须只有一行记录,而且只能有一列(又被称为标量子查询). 可以使用在select语句的列表.表达式中,以及where语句中等. ...
- SQL子查询/嵌套查询
sql子查询 嵌套SELECT语句 嵌套SELECT语句也叫子查询,一个 SELECT 语句的查询结果能够作为另一个语句的输入值.子查询不但能够出现在Where子句中,也能够出现在from子句中,作为 ...
- Sql Server的艺术(六) SQL 子查询,创建使用返回多行的子查询,子查询创建视图
子查询或内部查询或嵌套查询在另一个SQL查询的查询和嵌入式WHERE子句中. 子查询用于返回将被用于在主查询作为条件的数据,以进一步限制要检索的数据. 子查询可以在SELECT,INSERT,UPDA ...
- SQL Server温故系列(3):SQL 子查询 & 公用表表达式 CTE
1.子查询 Subqueries 1.1.单行子查询 1.2.多行子查询 1.3.相关子查询 1.4.嵌套子查询 1.5.子查询小结及性能问题 2.公用表表达式 CTE 2.1.普通公用表表达式 2. ...
- SQL查询优化思维即SQL子查询
一. 什么叫子查询 定义及分类 子查询又称内部查询,而包含子查询的语句称之外部查询(又称主查询).所有的子查询可以分为两类,即相关子查询和非相关子查询. 非相关子查询是独立于外部查询的子查询,子查询总 ...
- PL/SQL 子查询
一.概述 在一个SQL语句中嵌套另一个SQL语句成为子查询.包括单行子查询,多行子查询,多列子查询. 注意,当在DDL语句中引用子查询时,可以带有Order By子句:但是当在where子句.Set子 ...
- SQL 子查询,连接查询复习
use lianxi0720 go --创建部门表 create table bumen ( bcode int primary key,--部门编号 bname ), --部门名称 bceo ), ...
- sql子查询在insert、update、delete中的应用
子查询可以应用在INSERT.UPDATE以及DELETE等语句中,合理的使用子查询将能够简化功能的实现并且极大的提高SQL语句执行的效率 用到的表: CREATE TABLE `t_readerfa ...
随机推荐
- linux中MySQL本地可以连接,远程连接不上问题
1.网络或防火墙问题 (1)检查网络直接ping你的远程服务器,ping 182.61.22.107,可以ping通说明网络没问题 (2)看端口号3306是不是被防火墙挡住了,telnet 182.6 ...
- (转)python之并行任务的技巧
Python的并发处理能力臭名昭著.先撇开线程以及GIL方面的问题不说,我觉得多线程问题的根源不在技术上而在于理念.大部分关于Pyhon线程和多进程的资料虽然都很不错,但却过于细节.这些资料讲的都是虎 ...
- 微信小程序开发教程(一)准备
1.成为微信公众平台开发者 成为微信公众平台的开发者,是小程序开发的首要条件.只有成为微信公众平台的开发者,才可以使用公众平台的各种开发接口.如果你已经是开发者,则可以跳过本章. ①.进入微信公众平台 ...
- 【kd-tree】bzoj3290 Theresa与数据结构
离线所有操作,对所有可能存在的点建立kd-tree,add相当于权值+1,cancel相当于权值-1. 修改操作要记录kd-tree上每个点的fa,从底向上地进行修改. 优化:若一个矩形框的sumv= ...
- 【暴力】洛谷 P2038 NOIP2014提高组 day2 T1 无线网络发射器选址
暴力枚举. #include<cstdio> #include<algorithm> using namespace std; ][],d,n,x,y,z,num,ans=-; ...
- 前端基础-HTML标记语言
阅读目录 一. HTML标签与文档结构 二. HTML标签详细语法与注意点 三. HTML中标签分类 四. HTML注释 一. HTML标签与文档结构 HTML作为一门标记语言,是通过各种各样的标签来 ...
- java调用windows的wmi获取设备性能数据
java调用windows的wmi获取监控数据(100%纯java调用windows的wmi获取监控数据) 转:http://my.oschina.net/noahxiao/blog/73163 纯j ...
- Problem H: 计算数列和2/1,3/2,5/3,8/5......
#include<stdio.h> int main(){ int i,n; scanf("%d",&n); float sum=0.0; ; ; ;i< ...
- 开发板无法ping通虚拟机的问题解决一例
先描述一下遇到的问题: 使用的开发板是Tq2440,我将虚拟机和开发板都设在在了同一个网段,并且虚拟机使用的是桥接的方式,我用nfs的方式挂载根文件系统是失败,系统无法起来,后来我进入uboot命令模 ...
- firefox dispatchevent的问题
<!DOCTYPE html><html><head lang="en"> <meta charset="UTF-8&qu ...