设为首页 - 加入收藏 ASP站长网(Aspzz.Cn)- 科技、建站、经验、云计算、5G、大数据,站长网!
热搜: 创业者 数据 手机
当前位置: 首页 > 站长学院 > MySql教程 > 正文

搞清这些陷阱,NULL和三值逻辑再也不会作妖(2)

发布时间:2019-11-07 20:19 所属栏目:115 来源:youzhibing2904
导读:记住这个顺序后就能更方便地进行三值逻辑运算了。特别需要记住的是,当 AND 运算中包含 unknown 时,结果肯定不会是 true (反之,如果AND 运算结果为 true ,则参与运算的双方必须都为 true )。 --假设a=2,b=5,c=NU

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

  1. -- 假设 a = 2, b = 5, c = NULL,下列表达式的逻辑值如下 
  2.  
  3. a < b AND b > c  → unknown 
  4. a > b OR b < c   → unknown 
  5. a < b OR b < c   → true 
  6. NOT (b <> c)     → unknown 

“IS NULL” 而非 “= NULL”

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

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

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

-- 以下的式子都会被判为 unknown

  1. -- 以下的式子都会被判为 unknown 
  2. = NULL 
  3. > NULL 
  4. < NULL 
  5. <> NULL 
  6. NULL = NULL 

那么,为什么对 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 这样也许更合适。

温柔的陷阱

比较谓词和 NULL

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

假设我们有学生表:t_student:

  1. DROP TABLE IF EXISTS t_student; 
  2. CREATE TABLE t_student ( 
  3.     id INT(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', 
  4.     name VARCHAR(50) NOT NULL COMMENT '名称', 
  5.     age INT(3) COMMENT '年龄', 
  6.     remark VARCHAR(500) NOT NULL DEFAULT '' COMMENT '备注', 
  7.     primary key(id) 
  8. ) COMMENT '学生信息'; 
  9.  
  10. INSERT INTO t_student(name, age) 
  11. VALUE('zhangsan', 25),('wangwu', 60),('bruce', 32),('yzb', NULL),('boss', 18); 
  12.  
  13. SELECT * FROM t_student; 

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

  1. SELECT * FROM t_student 
  2. WHERE age = 20 OR age <> 20; 

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

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

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

  1. -- 1. 约翰年龄是 NULL (未知的 NULL !) 
  2. SELECT * 
  3. FROM t_student 
  4. WHERE age = NULL 
  5. OR age <> NULL; 
  6.  
  7. -- 2. 对 NULL 使用比较谓词后,结果为unknown 
  8. SELECT * 
  9. FROM t_student 
  10. WHERE unknown 
  11. OR unknown; 
  12.  
  13. -- 3.unknown OR unknown 的结果是unknown (参考三值逻辑的逻辑值表) 
  14. SELECT * 
  15. FROM t_student 
  16. WHERE unknown; 

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

(编辑:ASP站长网)

网友评论
推荐文章
    热点阅读