分享

SQL进价2:三值逻辑和null

 印度阿三17 2019-04-30

1、SQL中的bool类型的值有三种

普通编程语言里的布尔型只有 truefalse 两个值,这种逻辑体系被称为二值逻辑。而 SQL 语言里,除此之外还有第三个值 unknown,因此这种逻辑体系被称为三值逻辑(three-valued logic)。

2、null不是值,与数学运算符结果的结果永远是unknown

常听到的“列的值为 NULL” 、“NULL 值”这样的说法本身就是错误的。因为 NULL 不是值NULL 不是值NULL 不是值!(如果有人认为 NULL 是值,那么它是什么类型的值?关系数据库中存在的值必然属于某种类型,比如字符型或数值型等。所以,假如 NULL 是值,那么它就必须属于某种类型。)

另外,注意:要想和null比较只能用 is null 或者 is not null,这样才会返回true或者false。另外永远记住一点,null和<,<,=,<>这些放在一起结果永远是unknown,如 2=null,结果肯定是unknown,而unknown可在三值逻辑中不是true或者false,在写where子句的筛选条件时尤其要注意。举例来讲:

image

接下来我们总结一下 SQL 遵循的三值逻辑的真值规律(理解下面这些非常重要)。

先看下图:(t:true,f:false,u:unknown。not unknown 的结果是 unknown)

image

我们经常会遇到判断筛选条件的结果(为true/false/unknown的一种,且SQL只会取返回结果是true的记录),它们通常是and 或or连接这些单个条件的,如:where age>18 and sex=0或where age<18 and sex =unknown。所以我们要牢牢记住上面这个图,才能对各种情况下返回的数据心里有底。

记忆方式1:

and运算,只要有一边是unknown,另一边是false,那结果就是false,其它情况下,只要任意一边有unknown,结果就是unknown。

or运算,只要一边是unknown,那么结果永远就是unknown

记忆方式2:

在判断and或or的最终结果时,请注意true/false/unknown之间有下面这样的优先级顺序。

  • AND 的情况:falseunknowntrue

  • OR 的情况:trueunknownfalse

优先级高的真值会决定计算结果。例如 true AND unknown,因为 unknown 的优先级更高,所以结果是 unknown。而 true OR unknown 的话,因为 true 优先级更高,所以结果是 true。记住这个顺序后就能更方便地进行三值逻辑运算了。特别需要记住的是,当 AND 运算中包含 unknown 时,结果肯定不会是 true(反之,如果 AND 运算结果为 true,则参与运算的双方必须都为 true)。这一点对理解后文非常关键。

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

如果 NOT IN 子查询中用到的表里被选择的列中存在 NULL,则 SQL 语句整体的查询结果永远是空。EXISTS 谓词永远不会返回 unknownEXISTS 只会返回 true 或者 false。因此就有了 INEXISTS 可以互相替换使用,而 NOT INNOT EXISTS 却不可以互相替换的混乱现象。

4、ALL运算符与null

以下是ALL运算符语法:

scalar_expression comparison_operator ALL ( subquery )

在上面语法中,

  • scalar_expression是任何有效的表达式。

  • comparison_operator是任何有效的比较运算符,包括等于(=),不等于(<>),大于(>),大于或等于(>=),小于(<),小于或等于(<=)。

  • 括号内的子查询(subquery)是一个SELECT语句,它返回单个列的结果。 此外,返回列的数据类型必须与标量表达式的数据类型相同。

如果所有比较对(scalar_expression,v)的计算结果为TRUE,则ALL运算符返回TRUE; v是单列结果中的值。

如果其中一对(scalar_expression,v)返回FALSE,则ALL运算符返回FALSE

如果all里面的子查询返回的单列中有null的存在,那么这个all表达式就永远不会筛选出任何数据,结果肯定为空。

因为ALL 谓词其实是多个以 AND 连接的逻辑表达式的省略写法

如果all里面的子查询返回的单列中有null的存在,比如子查询结果如下面这个情况,那么具体的分析步骤如下所示。

--1. 执行子查询获取年龄列表
SELECT *
  FROM Class_A
 WHERE age < ALL ( 22, 23, NULL );
--2. 将ALL 谓词等价改写为AND
SELECT *
  FROM Class_A
 WHERE (age < 22) AND (age < 23) AND (age < NULL);
--3. 对NULL 使用“<”后,结果变为 unknown
SELECT *
  FROM Class_A
 WHERE (age < 22) AND (age < 23) AND unknown;
--4. 如果AND 运算里包含unknown,则结果不为true
SELECT *
  FROM Class_A
 WHERE false 或 unknown;
--5.查询结果为空

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多