mysql中关于exists的讲解

我认为exists语法是mysql中一个很强大的工具,可以简单地实现某些复杂的数据处理。

下面我谈谈与exists有关的三个方面。

all 与 any

首先,看到了exists,难免还会想到all和any,它们比exists容易理解一些。all 和 any都能让一行数据与多行数据进行比较,这是它们的主要功能。

create table T(X int);

insert into T(X) values(1),(2),(3),(4);

# eg.1

select * from T where X > all( select * from T where X < 3 );#输出3,4

# eg.2

select * from T where X > any( select * from T where X > 1 );#输出3,4

先看eg.1, 显然select * from T where X < 3结果是1,2;而all要求存在X大于集合{1,2}内的任意元素,即3,4。

同理,对于eg.2,select * from T where X > 1结果是2,3,4;any的要求是存在X大于集合{2,3,4}内的某个元素即可,即3,4。

划分表

在说exists之前,再看看一个比较特别的语句,关于表(table)的“划分”用法。

eg.1

# fruitTable

Id Name Class Count Date

1 苹果 水果 10 2011-7-1

1 桔子 水果 20 2011-7-2

1 香蕉 水果 15 2011-7-3

2 白菜 蔬菜 12 2011-7-1

2 青菜 蔬菜 19 2011-7-2

现在要求进行筛选,条件是Id唯一,Date选最近的一次

这种筛选条件潜藏着对于表的划分要求。以fruitTable为例,需要划分为2个子表,Id为1的为一个子表、Id为2的为另一个子表,再从各自子表里面选出时间最大的那个元组。

先看看下面一个错误的解法

SELECT DISTINCT Id, Name, Class, Count, Date FROM fruitTable t1

WHERE (Date IN

(SELECT MAX(Date) FROM fruitTable t2 GROUP BY Id));

# 结果

1 桔子 水果 20 2011-7-2

1 香蕉 水果 15 2011-7-3

2 青菜 蔬菜 19 2011-7-2

这周解法在逻辑上有漏洞。它将不同Id的最大时间混在了一起,没有真正地划分表格。

再来看看正确的解法

划分表格的思路是正确的,但问题是怎么划分,如果另外创建2个新的table,那这样显然太麻烦了,于是有了下面这种写法。

SELECT DISTINCT Id, Name, Class, Count, Date FROM fruitTable t1

WHERE (Date =

(SELECT MAX(Date) FROM fruitTable t2 WHERE t2.Id=t1.Id));

注意WHERE t2.Id=t1.Id 很巧妙地 对表t2 基于t2.Id=t1.Id这个标准 进行了划分。可以推导一下,比如遍历表t1,先是第1个元组:1 苹果 水果 10 2011-7-1, 可以知道t1.Id=1, 带入第2个select: (SELECT MAX(Date) FROM fruitTable t2 WHERE t2.Id=1) , 观察这个select语句的筛选条件WHERE t2.Id=1, 发现它的范围限定在了Id为1的元组内,聚集函数MAX(Date)返回Id为1的所有元组中Date最大的值(2011-7-3)。

因此对于表t1, 当t1.Id=1时,只有Date=2011-7-3的元组才会被选出来;而当tl.Id=2时,第2个select又变为SELECT MAX(Date) FROM fruitTable t2 WHERE t2.Id=2, 返会所有Id=2的元组中Date的最大值(2011-7-2)。

可以发现,表t2是受t1.Id控制的,根据t1.Id的不同而被划分为不同的子表,这就是表的划分,并且不需要另外创建新的表。

exists

先说说exists的基本用法

create table R(

X int, Y varchar(5), Z varchar(5)

);

create table S(

Y varchar(5), Z varchar(5), Q int

);

insert into R(X,Y,Z) values(

1,'a','A'

),(

1,'b','B'

),(

1,'a','B'

),(

1,'c','C'

),(

2,'a','B'

),(

2,'b','B'

),(

2,'c','A'

),(

3,'z','Z'

);

insert into S(Y,Z,Q) values(

'b','B',1

),(

'a','B',2

);

-----------------------------

select * from R where exists( select * from S where S.Y='b' and R.Y=S.Y );

# 结果

'1', 'b', 'B'

'2', 'b', 'B'

对于exists可以先简单地理解为if判断。

比如语句select * from R where exists( select * from S where S.Y='b' and R.Y=S.Y );就可以理解为 从表R中筛选出满足条件 S.Y='b' and R.Y=S.Y (select * from S where S.Y='b' and R.Y=S.Y) 的元组。

这个性质可以看出2个特性

首先exists()括号内的表不会影响最终返回的结果。比如上面的例子,返回的结果始终是关于表R的元组,和表S没有任何关系

对于exists()语句,关键的是括号内的where子句。对于exists( select * from S where S.Y='b' and R.Y=S.Y ) 这种语句,可以直接当作 if( S.Y== 'b' and R.Y ==S.Y )。当然也不是说select不重要,比如exists( select 1 from S where S.Y='b' and R.Y=S.Y )是永远为真的条件。

理清上面2点,我们就更能意识到exists非常像是一个关于条件判断的语句。

下面例子类似

# 选了张三老师课的学生

select distinct sc.sid from sc

where exists (

select * from course c,teacher t

where sc.cid = c.cid and c.tid = t.tid and t.tname = "张三");

但仅仅只有exists还不够,因为很多其它语句也能实现这个功能,真正强大的是not exists。

对于存在exists只是一个元组与某个局部作比较,因为只要存在即可。而对于不存在,却是一个元组和整体做比较,因为要确定不存在,就必须遍历所有。

在这方面来说,not exists比exists更强大。

找最值

SELECT DISTINCT Id, Name, Class, Count, Date FROM fruitTable t1

WHERE (Date =

(SELECT MAX(Date) FROM fruitTable t2 WHERE t2.Id=t1.Id));

#用not exists

SELECT DISTINCT Id, Name, Class, Count, Date FROM fruitTable t1

WHERE NOT EXISTS(

SELECT * FROM fruitTable t2 WHERE t2.Id=t1.Id and t2.Date > t1.Date );

这里not exists同样可以看作not if,关键是明白哪部分条件被否定(not)。根据之前的理论,这里条件明显是t2.Id=t1.Id and t2.Date > t1.Date , 而t2.Id=t1.Id不能作为否定的对象,因为这是必然存在的(自己想想,t1和t2内容一样),用来限定表t2的范围(即之前说的划分子表),再看t2.Date > t1.Date,这才是否定的部分,即对于t2中Id为t1.Id的所有元组的Date都不大于t1.Date,而此时的t1.Date也即最大值。

嵌套not exists

还有更复杂的情况,多层not exists嵌套使用。比如实现关系代数里的除法运算。

# 表R,S的定义上面已经给出 下面计算 R除以S

select distinct R1.x from R R1 where not exists (

select * from S where not exists (

select * from R R2 where R1.X=R2.X and R2.Y=S.Y and R2.Z=S.Z ));

一个not exists只表示不存在,需要遍历所有元组才能做出判断

2个not exists嵌套,表示每一个都存在,同样需要遍历所有元组才能确定,同时还是“肯定”

这里有3个select,2个not exists。

最里面的not exists是用来否定R2.Y=S.Y and R2.Z=S.Z (因为R1.X=R2.X一定成立,这个是用来划分子表的), 最外层的not exists就用来表示不存在这个意思,你会发现最后这个句子表达的意思就是关系代数里面除法的定义。

使用联合来解决exists问题

因为MySQL每次的操作都是基于行的,当涉及到表与表之间类似集合的关系时,处理起来比较麻烦。比如下面这个问题。

insert into R(X,Y) values(

1,'a'

),(

1,'b'

),(

1,'B'

),(

1,'C'

),(

2,'A'

),(

2,'c'

),(

3,'z'

);

insert into S(Y,Q) values(

'b',1

),(

'B',2

);

#问题:表R内,对于X值相同的行组成一组(或叫集合)。在这样的每组元素中,要求R(Y)中不能出现与S(Y)相同的值,求这样的组的X值有哪些。

#这种问题是关于集合之间的关系,不同于 一行与一个集合之间的关系。

#下面运用之前讲的not exists来求解

select distinct X from R R1 where not exists (

select * from R R2 where R2.X=R1.X and R2.Y in (select distinct Y from S));

下面来介绍另外一种方法,联合。

仔细观察可以发现R和S之间是有关系的,因此可以将它们进行自然连接,这样就直接得到了所有R(Y)=S(Y)的值。

select distinct X from R where X not in (select distinct X from R,S where R.Y=S.Y);

但是对于代码可读性来说,in和exists比派生表联合优雅

mysql的exists解析_mysql中关于exists的深入讲解相关推荐

  1. mysql获取当月最后一天_mysql中获取本月第一天、本月最后一天、上月第一天、上月最后一天

    mysql获取当月最后一天_mysql中获取本月第一天.本月最后一天.上月第一天.上月最后一天等等 转自: https://blog.csdn.net/min996358312/article/det ...

  2. mysql dns反向解析_Mysql DNS反向解析导致连接超时过程分析(skip-name-resolve)

    Mysql DNS反向解析导致连接超时过程分析(skip-name-resolve) 时间:2019-01-19 11:28作者:网友投稿 MySQL数据库收到一个网络连接后,首先拿到对方的IP地址, ...

  3. mysql 枚举 enum用法_mysql中的枚举类型ENUM的用法:

    mysql中的枚举类型ENUM的用法: (2010-06-18 13:44:13) mysql中的枚举类型ENUM的用法: mysql中的枚举类型ENUM是一个字符串对象,它的值是自表创建时在列规定中 ...

  4. mysql日期格式化季度_mysql中常用日期比较与计算函数

    MySql中时间比较的实现 unix_timestamp() unix_timestamp 函数可以接受一个参数,也可以不使用参数. 它的返回值是一个无符号的整数.不使用参数,它返回自1970年1月1 ...

  5. mysql表设计讲解_MySQL中数据库的设计归纳讲解

    谈到MySQL中数据库的设计,相信大家都知道这是实现实际业务的重要一步,因此对于Java学习者来说,深入了解和学习数据库的设计是十分有必要的.本文为大家准备了一份MySQL中数据库的设计归纳讲解,内容 ...

  6. mysql添加临时索引_mysql 中添加索引的三种方法

    在mysql中有多种索引,有普通索引,全文索引,唯一索引,多列索引,小伙伴们可以通过不同的应用场景来进行索引的新建,在此列出三种新建索引的方法 mysql 中添加索引的三种方法 1.1 新建表中添加索 ...

  7. mysql sql 时间比较_mysql中sql语句进行日期比较

    这里是一个使用日期函数的例子.下面的查询选择了所有记录,其date_col的值是在最后30天以内: mysql> SELECT something FROM table WHERE TO_DAY ...

  8. mysql if exists用法_MySQL中EXISTS的用法

    比如在Northwind数据库中有一个查询为 SELECT c.CustomerId,CompanyName FROM Customers cWHERE EXISTS(SELECT OrderID F ...

  9. mysql not exists优化_MySQL优化--NOT EXISTS和LEFT JOIN方式差异

    在MySQL中,我们可以将NOT EXISTS语句转换为LEFT JOIN语句来进行优化,哪为什么会有性能提升呢? 使用NOT EXISTS方式SQL为: SELECT count(1)FROMt_m ...

最新文章

  1. appium-chromedriver@3.0.1 npm ERR! code ELIFECYCLE npm ERR! errno 1
  2. 【动画2】CALayer动画
  3. 后赛门铁克时代Veritas加强数据保护应对欧盟法规
  4. 解决SQL Server 2000 错误15023:当前数据库中已存在用户或角色
  5. 初学者先学python语音好吗_献给Python初学者 零基础学习Python能学会吗
  6. 一个简单的你好,世界! 使用 Boost.MPI broadcast() 的示例
  7. java使用POI jar包读写xls文件
  8. .NET开发者必备的工具箱
  9. 框架选修课之dom4j解析xml字符串实例
  10. 如何更新 Linux 内核来提升系统性能
  11. 携程元旦出游数据:冰雪运动热度升级 张家口酒店一房难求
  12. Python采集深圳美莱(仅思路)
  13. 1m照片的宽和高是多少_照片常见标准尺寸大全
  14. 配置keepalived实现Nginx高可用(单主、双主模式)
  15. 适合高中生的计算机相关知识,高中生学习计算机知识的方向浅议.doc
  16. python英语词汇读音_40行Python代码区分英语单词和汉语拼音
  17. 微信公众平台数据统计
  18. 微信小程序《难忘便签》开发记录
  19. 正在播放2020Me比较特别的我_【一点资讯】电视剧播放指数榜单,《燕云台》有望成为爆款,只因这两点真不错 www.yidianzixun.com...
  20. WORD如何设置打印? 三分钟学会WORD打印技巧

热门文章

  1. 我的世界服务器地图缓存位置,地图(物品)是怎么存储的?以及提取地图数据的方法...
  2. 9012年马上结束了,安卓程序员们,还不准备跳槽留着过年么?
  3. JSP out 对象
  4. IT大败局----跋:愚蠢的发展战略
  5. 实用的微信小程序「值得推荐」
  6. redis错误:BeginForkOperation: system error caught. error code=0x000005af
  7. 蓝牙配对码配置错误_怎么用手机蓝牙给别人的手机传东西?
  8. DirectX7简单说明
  9. [系统与指令]系统指令集-防御之星
  10. 对于 CRC 校验的 学习笔记