大多数的编程语言都是基于二值逻辑(true,false),而SQL语言采用为三值逻辑(true,false,'unknown'),而这个不确定因素常常导致查询结果并不是理想中的结果。总之存在null那么查询结果就无法保证一定正确。

为什么采用三值逻辑?因为关系数据库中引进了NULL!!!

两种NULL的定义:“未知(unknown)”和“不适用(not applicable,not inapplicable)”;

未知:不知道戴墨镜的人眼睛是什么颜色,颜色一定存在只是并不知道。

不适用:不知道冰箱的眼睛是什么颜色,冰箱根本没有眼睛所以“眼睛颜色”并不适用。

1,为什么在SQL中使用“ = NULL”报错而非要使用“IS NULL” 

解:一旦使用了比较谓词(=,>,<,<>)那么得到的结果总为unknown,而查询结果只包含了true数据行,并不会包含false与unknown数据行。

NULL:既不是值也不是变量,NULL只是一个表示“没有值“的一个标记,而比较谓词只适用于值,因此对于非值的NULL来使用比较谓2词并没有什么意义;

2,unknown

真值unknown和作为NULL的一种unknown(未知)并不是相同的东西,前者为布尔值的真值,后者既不是值也不hi变量,为了区分前者采用小写后者采用大写。

当x=x等式中

x=真值unknown时,unknown=unknow判断为true。

x=UNKNOWN时,UNKNOWN=UNKNOWN判断为null;

SQL遵循的三值逻辑真值表:

NOT:比较简单;

AND:false>unknown>true;

OR:true>unknown>false;

优先级高的真值决定计算结果,列如:true AND nuknown:结果为unknown(优先级更高),true OR unknown:结果为:true;

当AND运算中包含unknown,结果肯定不会为true,如果AND运算结果为TURE,则参与的双方都必须为true;

问题:假设a=2,b=5,c=null;

a<b AND b>c : true and unknown   :unknown

a>b or b>c :     false and unknown  :  unknown

a<b or b<c:      ture and nuknown    : true

NOT(b<>c):     not( nuknown)  : unknown

3.实践内容:

1,比较谓词和NULL(1):排中率不成立

问题描述:假设李四时一个人,那么下面语句是真是假?

李四是20岁,或者不是20岁,二者必居其一!

你觉得这句话正确吗,在现实中是真命题。我们不知道李四是谁,但是知道李四是人,只要是人就有年龄,要么就是20岁要么就不是20岁,不可能还有其他情况。

像这样,“把命题和 它的否命题通过‘或者’连接而成的命题全都是真命题”这个命题在二 值逻辑中被称为排中律(Law of Excluded Middle)。顾名思义,排中 律就是指不认可中间状态,对命题真伪的判定黑白分明,是古典逻辑 学的重要原理。(摘抄)

假设SQL中排中律也成立,那么下面查询应该能选中表里的所有行?

SELECT * FROM USER
WHERE AGE = 20 OR AGE != 20;

SQL世界中排中率并不存在,如果一个表里有NULL值那么就不会将其全部查询出来;

2,比较谓词和NULL:CASE表达式和NULL

SELECT
CASE PRICE WHEN 50 THEN 'O'WHEN NULL THEN 'X'
END
from products2

解:CASE表达式一定不会返回X,第二格WHEN子句时price = NULL的缩写,这个式子真值永远是unknown,而且CASE判断方式与WHERE一致。只认可真值为true的条件。

SELECT
CASE  WHEN price = 50 THEN 'O'WHEN price IS NULL THEN 'X'
END
from products2

3,NOT IN 和 NOT EXISTS不是等价的

性能优化时,经常将IN改写为EXISTS,这是等价改写,但是将NOT IN 改为NOT EXISTS时结果却未必一致;

-- 问题:查找2班住在南京的学生年龄不同于1班的学生!
select * from class1
where age not in( select age from class2 where city='南京')
-- 注意:当判断存在NULL值的时使用上面SQL无法正常查询,但是无NULL就可以正常查询--详细查询
SELECT * FROM CLASS1 WHERE AGE NOT IN (22,23,null)
-- 用NOT 和IN 等价改写NOT IN
select * from class1 where not age in (22,23,null)
-- 用OR 等价改写谓词IN
select * from class1 where not( (age = 22) and not (age =23) and not (age =null))
-- 使用德· 摩根定律等价改写
select * from class1 where not (age =22) and not(age=23) and not(age = null)
-- 用<> 等价改写 NOT 和 =
select * from class1 where (age <> 22) AND (age <> 23) AND (age <> NULL);
-- 对NULL 使用<> 后,结果为unknown
select * from class1 where (age <> 22) AND (age <> 23) AND unknown;
-- 如果AND 运算里包含unknown,则结果不为true(参考“理论篇”中的矩阵)
select * from class1 where false or nuknown

结果用OR 等价改写谓词IN成功查询出结果!(MYSQL)

从这里看出没有一行在WHERE子句判断为true,如果NOT IN 子句查询中用到表中被选择的字段中存在NULL,则SQL查询永远为空!

4,采用EXISTS谓词

-- 查找2班住在南京,但是学生年龄不同的A班学生;
-- 结果为:1班年龄不等于2班住在南京学生的年龄
select * from class1 a
where not exists (select * from class2 b where a.age = b.age and b.city = '南京' )

我们详细查看年龄为NULL的数据行如何处理的!

-- 1,子查询里和NULL做比较运算
select * from class1 a where not exists (select * from class2 b where a.age = null and  b.city = '南京'
)
-- 2. 对NULL 使用“=”后,结果为 unknown
select * from class1 a
where not exists (select * from class2 b where 'unknown' and b.city = '南京' )
-- -3. 如果AND 运算里包含unknown,结果不会是true
where not exists (select * from class2 b where false or 'unknown' )

EXISTS语句并不会返回unknown,只会返回false和true。因此有了IN和EXISTS可以相互交替使用而NOT EXISTS 和 NOT IN 无法相互替换使用。

5,限定谓词和NULL

SQL中存在ALL和ANY两个限定谓词,因此ANY和IN是等价的,所以我们不常使用ALL;

ALL可以和比较谓词一起使用,来表达“与所有的XX相等”或者“比所有的XX都大“的意思!

接下来将1班和2班NULL值填充一下,然后使用此表来思考下”查询比2班住在南京的所有学生年龄都小的A班学生“的SQL语句

select * from class1
where age > all (select age from class2 where city = '南京')

查询出的结果都是比all(age)大的数据行;

-- 执行子查询结果获取年龄列表  MYSQL(语法报错)
select * from class1 where age < all(22,23,null)
-- 将ALL改写and    无结果
select * from class1 where (age>23) and (age > 22) and (age > null)
--  对NULL 使用“<”后,结果变为 unknown   MYSQL(语法报错)
SELECT * FROM Class1 WHERE (age < 22) AND (age < 23) AND unknown;
--  如果AND 运算里包含unknown,则结果不为true    无结果
SELECT * FROM Class1 WHERE false or 'unknown';

NULL的值导致很多问题,从上面的一些SQL也体会了吧!

6,限定谓词和极值函数不是等价的

使用极值函数来改写SQL

-- 查询比B班住在南京的年龄最小的学生还要小的A班学生
select * from class1 where age <(select min(age) from class2 where city = '南京')

会发现,即使存在NULL值也不会影响SQL的查询结果,因为极值函数会将NULL值排除掉!

但是使用ALL谓词时如果2班没有南京的学生将查询到所有的1班学生!

select * from class1 where age < all(select age from class2 where city = '上海')

如果使用极值函数那么将一个都查询不出来;

select * from class1 where age < (select min(age) from class2 where city = '上海')

极值函数本质上就是 age < null

7,聚合函数和NULL

实际上,输入为空表时返回NULL的不只是极值函数,COUNT以外的聚合函数也是如此!!

本节总结:

1.NULL不是值

2.因为NULL不是值所以不能使用谓词(>,<,!=)

3.对NULL使用谓词结果就是unknown

4.unknown参与逻辑运算时,SQL运算结果会和预想的不一致

5.解决NULL带来的问题就是NOT NULL 约束

问题总结:

Q:为什么WHERE co l_1 = NULL 会出错?
A:NULL不是值,只是一个“没有值”的标记,需要用 where col_1 is null;

select * from class1 where age = null;  -- 结果为空

select * from class1 where age is null;

Q:排中律在SQL中是否成立?(排中律:一个人年龄要么等于20,要么不等于20)
A:在SQL中,排中律不存在

select * 
    from class1
    where age = 20 
    or age <> 20;     -- 无法查询出年龄为NULL的学生

Q:CASE表达式中,NULL应该怎么写?
A:搜索表达式 + IS NULL
SELECT 
CASE  
    WHEN price = 50 THEN 'O'
    WHEN price IS NULL THEN 'X' 
END 
from products2

NOT IN  和 NOT EXSIST不等价  

Q:查询“与B班住在东京的学生年龄不同的A班学生”,即“拉里”和“伯杰”
A:不能用NOT IN

  • NOT IN:在子查询存在NULL时,查询结果永远为空
  • NOT EXISTS:不受子查询中NULL影响

限定谓语 (ALL、ANY) 和NULL

Q:ANY相当与IN;ALL和比较谓语联用表示“与所有的XX都相等”、“比所有的XX都大”,若遇到NULL
A:若ANY、ALL遇到NULL,查询结果永远为空

极值函数 (MAX、MIN) 和NULL

Q:MAX和比较谓语联用表示“比XXX里最大的更大”,若遇到NULL
A:极值函数只对非NULL起作用

  • 若少量值为NULL,则MAX表示“比XXX剩下非NULL里最大的更大”;
  • 若整个子查询为NULL,则查询结果为空

聚集函数 (COUNT、AVG) 和NULL

了COUNT(*),其他聚集函数与极值函数一样,只对非NULL起作用

SQL进阶之路03:三值逻辑和NULL相关推荐

  1. MICK-SQL进阶教程 1.3 三值逻辑和NULL

    让自己愈发觉得自己学艺不精的一章... 要点: 三值逻辑:true, false, unknown 必须写成"IS NULL",而不是"= NULL":对 NU ...

  2. SQL三值逻辑和NULL

    三值逻辑: 真.假和"不确定值" 三值逻辑和布尔型类型的区别: 普通布尔类型只有true和false两个值,这种逻辑体系被称为二值逻辑. 在SQL语言中还有第三个值:unknown ...

  3. 【第21天】SQL进阶-查询优化- performance_schema系列三:事件记录(SQL 小虚竹)

    回城传送–><32天SQL筑基> 文章目录 零.前言 一.练习题目 二.SQL思路 SQL进阶-查询优化- performance_schema系列三:事件记录 等待事件表 even ...

  4. 黎想深度访谈腾讯顶级产品经理的进阶之路——第三篇《需求》

    16个月精心打磨,9位顶级产品专家研讨提炼,凝聚腾讯产品经验的八集八分钟产品课分别从用户.定位.需求.时机.匠心.危机.合作.商业角度出发,还原产品背后的故事,分享给你腾讯产品的心法.艺形艺意工作室创 ...

  5. c语言野指针导致问题,C语言进阶之路(三)----野指针的产生原因及解决办法

    1.会产生野指针的做法 #include //这就是一种错误的写法 int main(){ int *p = NULL; p = (int *)malloc(); //释放P所指向的内存空间,但指针变 ...

  6. 【MySQL】MySQL进阶之路(三)MySQL基础知识点整理

    写在前面的话 脑子是个好东西,可惜的是一直没有搞懂脑子的内存删除机制是什么,所以啊,入行多年,零零散散的文章看了无数,却总是学习了很多也忘了很多. 痛定思痛的我决定从今天开始系统的梳理下知识架构,记录 ...

  7. [转]工程师进阶之路(三)

    2019独角兽企业重金招聘Python工程师标准>>> 工程师进阶之路 三 再谈沟通的策略 什么叫做策略,我的认识就是做事情的方法,有些时候光有很好的原则,而没有好的方法也是不行的. ...

  8. 如何在SQL分组查询时将空白值和NULL值分为一组

    问题背景 出现这个问题的原因是在测试过程中,对于我要分组的类型在不同人存数据时出现了空白值和NULL两种情况(胡闹!),导致我之前的分组查询会出现NULL一个分组,空白值一个分组,由于业务上的需求是没 ...

  9. python的进阶之路_Python 从入门到进阶之路(三)

    在之前的文章我们介绍了一下 Python 中 if while for 的使用,本章我们来看一下 Python 中的变量类型. 在 Python 定义变量时的规则是 变量名 = 变量 ,Python ...

最新文章

  1. mysql在linux下的安装_mysql在linux下的安装
  2. NIPS 2016 Highlighted Papers
  3. 【cocos2d-x】2.0升级为3.0一些常见变化纪录
  4. Cacti迁移RRA数据迁移脚本
  5. The size of tensor a (4) must match the size of tensor b (3) at non-singletonThe size of
  6. Python语法糖之:列表解析、集合解析和字典解析
  7. 上学吧在线计算机考试中心题库,上学吧考试题库
  8. 连昌宫词 [唐] 元稹
  9. L1-072 刮刮彩票 (20 分)-PAT 团体程序设计天梯赛 GPLT
  10. codeforce 837C
  11. Dev cpp出现段错误的原因之一
  12. rapidxml解析类
  13. opencv中关于cvtColor函数性能测试
  14. Win10自带浏览器MicroEdge无法打开网页---解决办法
  15. IDEA如何新建一个source folder
  16. 手机科普(软硬件简介——android)看了会懂很多东西的!
  17. get busy trying or get busy dying
  18. 哈工大车万翔:自然语言处理范式正在变迁
  19. win10笔记本外接显示器后,微信界面字体模糊问题的解决方案
  20. Adaptive Spectrum Noise Cancellation (自适应频谱噪声消除 ,ASNC)去除强运动伪影

热门文章

  1. 全球室内设计界NO.1力作!东呈联合HBA打造柏曼酒店;万豪集团在上海开设第五家福朋喜来登酒店 | 美通社头条...
  2. linux nas 数据恢复,NAS网络存储数据误删了怎么恢复
  3. 我与CSDN的故事《相遇、相知、相爱、相守》
  4. 《生物信息学:导论与方法》----导论与历史----听课笔记(一)
  5. IDEA入门教程----是时候舍弃Eclipse了
  6. 关于九针串口的公头和母头
  7. Win 10多屏显示设置教程 游戏多屏合一显示(超详细)
  8. mac同时享受教育优惠和免手续费分期
  9. CPU 缓存一致性 MESI 协议
  10. mysql.js回调函数_js回调函数(callback)