NULL 用于表示缺失的值或遗漏的未知数据,不是某种具体类型的值。数据表中的 NULL 值表示该值所处的字段为空,值为 NULL 的字段没有值,尤其要明白的是:NULL 值与 0 或者空字符串是不同的。

这种说法大家可能会觉得很奇怪,因为 SQL 里只存在一种 NULL 。然而在讨论 NULL 时,我们一般都会将它分成两种类型来思考:“未知”(unknown)和“不适用”(not applicable,inapplicable)。

以“不知道戴墨镜的人眼睛是什么颜色”这种情况为例,这个人的眼睛肯定是有颜色的,但是如果他不摘掉眼镜,别人就不知道他的眼睛是什么颜色。这就叫作未知。

而“不知道冰箱的眼睛是什么颜色”则属于“不适用”。因为冰箱根本就没有眼睛,所以“眼睛的颜色”这一属性并不适用于冰箱。“冰箱的眼睛的颜色”这种说法和“圆的体积”“男性的分娩次数”一样,都是没有意义的。

平时,我们习惯了说“不知道”,但是“不知道”也分很多种。“不适用”这种情况下的 NULL ,在语义上更接近于“无意义”,而不是“不确定”。

这里总结一下:“未知”指的是“虽然现在不知道,但加上某些条件后就可以知道”;而“不适用”指的是“无论怎么努力都无法知道”。

关系模型的发明者 E.F. Codd 最先给出了这种分类。下图是他对“丢失的信息”的分类。

为什么必须写成“IS NULL”,而不是“= NULL”?我相信不少人有这样的困惑吧,尤其是相信刚学 SQL 的小伙伴。我们来看个具体的案例,假设我们有如下表以及数据:

我们要查询备注为 NULL 的记录(为 NULL 这种叫法本身是不对的,只是我们日常中已经叫习惯了,具体往下看),怎么查,很多新手会写出这样的 SQL:

执行时不报错,但是查不出我们想要的结果, 这是为什么 ?这个问题我们先放着,我们往下看。

这个三值逻辑不是三目运算,指的是三个逻辑值,有人可能有疑问了,逻辑值不是只有真(true)和假(false)吗,哪来的第三个?

说这话时我们需要注意所处的环境,在主流的编程语言中(C、JAVA、Python、JS等)中,逻辑值确实只有 2 个,但在 SQL 中却存在第三个逻辑值:unknown。这有点类似于我们平时所说的:对、错、不知道。

逻辑值 unknown 和作为 NULL 的一种的 UNKNOWN (未知)是不同的东西。前者是明确的布尔型的逻辑值,后者既不是值也不是变量。

为了便于区分,前者采用小写字母 unknown ,后者用大写字母 UNKNOWN 来表示。为了让大家理解两者的不同,我们来看一个 x=x 这样的简单等式。x 是逻辑值 unknown 时,x=x 被判断为 true ,而 x 是 UNKNOWN 时被判断为 unknown 。

NOT:

AND:

OR:

图中蓝色部分是三值逻辑中独有的运算,这在二值逻辑中是没有的。其余的 SQL 谓词全部都能由这三个逻辑运算组合而来。从这个意义上讲,这个几个逻辑表可以说是 SQL 的母体(matrix)。

NOT 的话,因为逻辑值表比较简单,所以很好记;但是对于 AND 和 OR,因为组合出来的逻辑值较多,所以全部记住非常困难。为了便于记忆,请注意这三个逻辑值之间有下面这样的优先级顺序:

  • AND 的情况:false > unknown > true;

  • OR 的情况:true > unknown > false。

优先级高的逻辑值会决定计算结果。例如 true AND unknown ,因为 unknown 的优先级更高,所以结果是 unknown 。而 true OR unknown 的话,因为 true 优先级更高,所以结果是 true 。

记住这个顺序后就能更方便地进行三值逻辑运算了。特别需要记住的是,当 AND 运算中包含 unknown 时,结果肯定不会是 true (反之,如果AND 运算结果为 true ,则参与运算的双方必须都为 true )。

我们再回到问题:为什么必须写成“IS NULL”,而不是“= NULL”?

对 NULL 使用比较谓词后得到的结果总是 unknown 。而查询结果只会包含 WHERE 子句里的判断结果为 true 的行,不会包含判断结果为 false 和 unknown 的行。不只是等号,对 NULL 使用其他比较谓词,结果也都是一样的。

所以无论 remark 是不是 NULL ,比较结果都是 unknown ,那么永远没有结果返回。以下的式子都会被判为 unknown:

那么,为什么对 NULL 使用比较谓词后得到的结果永远不可能为真呢?

这是因为,NULL 既不是值也不是变量。NULL 只是一个表示“没有值”的标记,而比较谓词只适用于值。

因此,对并非值的 NULL 使用比较谓词本来就是没有意义的。“列的值为 “NULL ”、“NULL 值” 这样的说法本身就是错误的。因为 NULL不是值,所以不在定义域(domain)中。

相反,如果有人认为 NULL 是值,那么我们可以倒过来想一下:它是什么类型的值?关系数据库中存在的值必然属于某种类型,比如字符型或数值型等。所以,假如 NULL 是值,那么它就必须属于某种类型。

NULL 容易被认为是值的原因有两个。

第一个是高级编程语言里面,NULL 被定义为了一个常量(很多语言将其定义为了整数0),这导致了我们的混淆。但是,SQL 里的 NULL 和其他编程语言里的 NULL 是完全不同的东西。

第二个原因是,IS NULL 这样的谓词是由两个单词构成的,所以我们容易把 IS 当作谓词,而把 NULL 当作值。特别是 SQL 里还有 IS TRUE 、IS FALSE 这样的谓词,我们由此类推,从而这样认为也不是没有道理。但是正如讲解标准 SQL 的书里提醒人们注意的那样,我们应该把 IS NULL 看作是一个谓词。因此,写成 IS_NULL 这样也许更合适。

排中律不成立。排中律指同一个思维过程中,两个相互矛盾的思想不能同假,必有一真,即“要么A要么非A”。

假设我们有学生表:t_student:

表中数据 yzb 的 age 是 NULL,也就是说 yzb 的年龄未知。在现实世界里,yzb 是 20 岁,或者不是 20 岁,二者必居其一,这毫无疑问是一个真命题。那么在 SQL 的世界里了,排中律还适用吗? 我们来看一个 SQL :

咋一看,这不就是查询表中全部记录吗?我们来看下实际结果:

yzb 没查出来,这是为什么?我们来分析下,yzb 的 age 是 NULL,那么这条记录的判断步骤如下:

SQL 语句的查询结果里只有判断结果为 true 的行。要想让 yzb 出现在结果里,需要添加下面这样的 “第 3 个条件”:

CASE 表达式和 NULL。简单 CASE 表达式如下:

这个 CASE 表达式一定不会返回 ×。这是因为,第二个 WHEN 子句是 col_1 = NULL 的缩写形式。正如我们所知,这个式子的逻辑值永远是 unknown ,而且 CASE 表达式的判断方法与 WHERE 子句一样,只认可逻辑值为 true 的条件。正确的写法是像下面这样使用搜索 CASE 表达式:

我们在对 SQL 语句进行性能优化时,经常用到的一个技巧是将 IN 改写成 EXISTS ,这是等价改写,并没有什么问题。但是,将 NOT IN 改写成 NOT EXISTS 时,结果未必一样。

我们来看个例子,我们有如下两张表:t_student_A 和 t_student_B,分别表示 A 班学生与 B 班学生。

需求:查询与 A  班住在深圳的学生年龄不同的 B 班学生,也就说查询出 :马化腾 和 李彦宏,这个 SQL 该如何写,像这样?

我们来看下执行结果:

我们发现结果是空,查询不到任何数据,这是为什么 ?这里 NULL 又开始作怪了,我们一步一步来看看究竟发生了什么。

可以看出,在进行了一系列的转换后,没有一条记录在 WHERE 子句里被判断为 true 。也就是说,如果 NOT IN 子查询中用到的表里被选择的列中存在 NULL ,则 SQL 语句整体的查询结果永远是空。这是很可怕的现象!

为了得到正确的结果,我们需要使用 EXISTS 谓词。

执行结果如下:

同样地,我们再来一步一步地看看这段 SQL 是如何处理年龄为 NULL 的行的:

也就是说,yzb 被作为 “与任何人的年龄都不同的人” 来处理了。EXISTS 只会返回 true 或者false,永远不会返回 unknown。因此就有了 IN 和 EXISTS 可以互相替换使用,而 NOT IN和 NOT EXISTS 却不可以互相替换的混乱现象。

还有一些其他的陷阱,比如:限定谓词和 NULL、限定谓词和极值函数不是等价的、聚合函数和 NULL 等等。

1、NULL 用于表示缺失的值或遗漏的未知数据,不是某种具体类型的值,不能对其使用谓词。

2、对 NULL 使用谓词后的结果是 unknown,unknown 参与到逻辑运算时,SQL 的运行会和预想的不一样。

3、 IS NULL 整个是一个谓词,而不是:IS 是谓词,NULL 是值;类似的还有 IS TRUE、IS FALSE。

4、要想解决 NULL 带来的各种问题,最佳方法应该是往表里添加 NOT NULL 约束来尽力排除 NULL。

我的项目中有个硬性规定:所有字段必须是 NOT NULL,建表的时候就加上此约束。

  • 《SQL进阶教程》

作者丨youzhibing2904
来源丨www.cnblogs.com/youzhibing/p/11337745.html

搞清这些陷阱,NULL和三值逻辑再也不会作妖相关推荐

  1. 第一百零四期:搞清这些陷阱,NULL和三值逻辑再也不作妖

    NULL 用于表示缺失的值或遗漏的未知数据,不是某种具体类型的值.数据表中的 NULL 值表示该值所处的字段为空,值为 NULL 的字段没有值,尤其要明白的是:NULL 值与 0 或者空字符串是不同的 ...

  2. 质量报表 : 再也不用加班作报告

    关键词:质量报表,质量报告 虽然无比怀念那个悠长又幸福的春节假期,但该来的总要来.终于,终于要开工啦! 领导:明天客户审核,SPC的报告都准备好了吗? 惊讶表情 领导:下周质量月会,这周抽空把报告都准 ...

  3. 阅读目录(置顶)(长期科技领域知识)

    第一期:适用于数据项目的7种强大的开源工具 第二期:四种正确的微服务部署方式 第三期:开源和赚钱何去何从 第四期:Web前端和Java开发哪个薪资更高,发展前景更好? 第五期:干货总结:中级前端工程师 ...

  4. 如何禁止小孩玩游戏? 程序员教你一招!

    我们经常看到新闻上面报道熊孩子偷玩父母手机,玩游戏花光父母几十万积蓄,心酸又无奈,今天小编给各位家长带来最终解决方案. 此软件可以禁止小孩玩游戏,禁止手机安装游戏,帮助因沉迷游戏影响生活和学习的小孩的 ...

  5. 程序员的创业陷阱:接私活

    我本身是 Java 工程师出身,写代码至今已超过 15 年,创业也超过 10 年,曾经外包过很多项目给别人,也接过很多外包的项目,现在不接了,只经营电子报发送平台,在二年内累积超过 5000 家企业用 ...

  6. [No00004C]软件工程师的创业陷阱:接私活

    我本身是 Java 工程师出身,写代码至今已超过 15 年,创业也超过 10 年,曾经外包过很多项目给别人,也接过很多外包的项目,现在不接了,只经营电子报发送平台,在二年内累积超过 5000 家企业用 ...

  7. 创业陷阱——逐一点评301个骗你没商量的项目

    创业陷阱--逐一点评301个骗你没商量的项目 1.灵芝栽培:技术是真的.但是,骗子把收购价格提高了成千上万倍,说什么种植2平方米,年收十几万.还搞个什么回收合同,其实都是幌子. 2.冬虫夏草:技术还不 ...

  8. 转:领导者的三大陷阱:禁不住诱惑、控不住谎言、克制不住恐吓

    个人理解: 自我觉察.自我塑造,和人性的弱点做斗争 一个领导者最有力量的话,三个字--"我错了" 同一组织的人,走到最后,其实是一群人的价值观选择 上级可以批评下属,但得就事论事, ...

  9. Spark开发注意: collect_list、collect_set会去除Null值

    今天我们踩到一个collect_list的坑,collect_list的结果不包含null值 name city 张三 广州 null 广州 李四 深圳 对city作group by后collect_ ...

最新文章

  1. 帝国cms后台模板编辑器辅助增强插件代码高亮格式化显示
  2. Type difference of character literals in C and C++
  3. python做些什么-学会Python后都能做什么?网友们的回答简直不要太厉害
  4. Sicily 6768. Log Books 解题报告
  5. 如何避免jps中一大堆spark-submit+Spark交互模式启动速度+正确的退出spark-shell/pyspark/SparkR/hbase的习惯
  6. opencv3/C++ 机器学习-SVM应用实例:药品(胶囊)识别与分类
  7. 用nginx转发请求tomcat 如何配置访问日志获取真实ip
  8. 基于thinkphp的出租屋管理系统升级版
  9. 手机端如何破解wifi密码
  10. bootloader 解析
  11. Linux使用Maven部署SpiderFlow爬虫平台
  12. Appium工作日记:Message: An element could not be located on the page using the given search parameters.
  13. 人脸识别(Facenet)
  14. 电信短信网关ISAG-SMS二次开发
  15. R语言获取丁香园疫情数据动态网站
  16. 每天10道Crypto Day 2
  17. java开发微信如何维护登录状态_微信小程序中做用户登录与登录态维护的实现详解...
  18. Excel使用SQL进行查询
  19. Flutter 实现虚线
  20. 简述园路的功能作用_园林设计中园路的功能

热门文章

  1. 你不了解PHP的10件事情
  2. 人工智能数学基础知识
  3. 谷歌浏览器外贸版_做外贸快两个月,没有单怎么办?
  4. php记录已经点击过,最近一次的PHP面试题记录,office已到手!
  5. java 观察者模式_Java技术干货分享:深入理解观察者模式原理与技术
  6. mysql性能结构优化原理_MySQL性能管理及架构设计(二):数据库结构优化、高可用架构设计、数据库索引优化...
  7. 去除lcd图片的摩尔纹_宝妈时尚产后有妊娠纹怎么办?教你这三招,轻松修复肚皮!...
  8. java-多线程操作全(Thread)-Timer简单使用
  9. remove()与empty()的区别
  10. 数据结构——各排序算法的比较