让自己愈发觉得自己学艺不精的一章、、、

要点:

  • 三值逻辑:true, false, unknown

  • 必须写成“IS NULL”,而不是“= NULL”:对 NULL 使用比较谓词后得到的结果总 是 unknown。而查询结果只会包含 WHERE 子句里的判断结果为 true 的行, 不会包含判断结果为 falseunknown 的行。

  • NULL 既不是值也不是变量。NULL 只是一个表示“没有值”的 标记,而比较谓词只适用于值。因此,对并非值的 NULL 使用比较谓词本来就是没有意义的 。

    真值 unknown 和作为 NULL 的一种的 UNKNOWN(未知)是不同的东西。前者是明确的布尔型的真值,后者既不是值也不 是变量。为了便于区分,前者采用粗体的小写字母 unknown,后者用普通 的大写字母 UNKNOWN 来表示。

  • 真值的优先级排序

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

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

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

-- col_1 为 1 时返回○、为 NULL 时返回 × 的 CASE 表达式?
CASE col_1
WHEN 1 THEN '○'
WHEN NULL THEN '×' END
-- 这个 CASE 表达式一定不会返回 ×。这是因为,第二个 WHEN 子句 是 col_1 = NULL 的缩写形式。正如大家所知,这个式子的真值永 远是 unknown。而且 CASE 表达式的判断方法与 WHERE 子句一样,只 认可真值为 true 的条件。
-- 正确的写法是像下面这样使用搜索 CASE 表 达式。
CASE WHEN col_1 = 1 THEN '○' WHEN col_1 IS NULL THEN '×'
END

NOT IN 和 NOT EXISTS 不是等价的

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

-- 选择“与 B 班(class_b,包含空值)住在东京的学生年龄不同的 A 班(class_a)学生”
-----------------------------------------------------
-- 错误写法
select name
from class_a
where age not in (select age in class_b where city = '东京');
-- 结果:空
-----------------------------------------------------
-- 执行原理--1. 执行子查询,获取年龄列表 SELECT *FROM Class_AWHERE age NOT IN (22, 23, NULL);--2.用NOT和IN等价改写NOT IN SELECT *FROM Class_AWHERE NOT age IN (22, 23, NULL);--3. 用 OR 等价改写谓词 IN SELECT *FROM Class_AWHERE NOT ( (age = 22) OR (age = 23) OR (age = NULL) );--4. 使用德 · 摩根定律等价改写 SELECT *FROM Class_AWHERE NOT (age = 22) AND NOT(age = 23) AND NOT (age = NULL);--5.用<>等价改写 NOT和 = SELECT *FROM Class_AWHERE (age <> 22) AND (age <> 23) AND (age <> NULL);--6. 对 NULL 使用 <> 后,结果为 unknown SELECT *FROM Class_AWHERE (age <> 22) AND (age <> 23) AND unknown;--7.如果 AND 运算里包含 unknown,则结果不为 true SELECT *FROM Class_AWHERE false或unknown;
-----------------------------------------------------

也就是说,如果 NOT IN 子查询中用到的表里被选择的列中存在 NULL,则 SQL 语句整体的查询结果永远是空。

-- 正确写法
select name
from class_a
where age not exists (select age in class_b where city = '东京');
-----------------------------------------------------
-- 原理--1. 在子查询里和NULL进行比较运算select *from Class_A Awhere not exists (select * from Class_B B where A.age = NULL and B.city = '东京');--2.对NULL使用“=”后,结果为 unknownSELECT *FROM Class_A AWHERE NOT EXISTS (SELECT *FROM Class_B B WHERE unknown AND B.city = '东京')--3. 如果 AND 运算里包含 unknown,结果不会是 trueSELECT *FROM Class_A AWHERE NOT EXISTS ( SELECT *FROM Class_B BWHERE false或unknown);--4.子查询没有返回结果,因此相反地,NOT EXISTS为true SELECT *FROM Class_A A WHERE true;
-----------------------------------------------------

产生这样的结果,是因为 EXISTS 谓词永远不会返回 unknown。EXISTS 只会返回 true 或者 false。因此就有了 IN 和 EXISTS 可以互相替换使用,而 NOT IN 和 NOT EXISTS 却不可以互 相替换的混乱现象。

限定谓词和 NULL

SQL 里有 ALL 和 ANY 两个限定谓词。因为 ANY 与 IN 是等价的,所以 我们不经常使用 ANY。ALL 可以和比较谓词一起使用,用来表达“与所有的 ×× 都相等”, 或“比所有的 ×× 都大”的意思。

-- 查询比 B 班住在东京的所有学生年龄都小的 A 班学生
-----------------------------------------------------
-- b表中不含Null时
SELECT *
FROM Class_A
WHERE age < ALL ( SELECT agefrom Class_BWHERE city = '东京')
-- 结果:正确
-----------------------------------------------------
-- b表中含Null时
-- 结果:空
-- 原理:ALL 谓词其实是多个以 AND 连接的逻辑表达式的省略写法。--1. 执行子查询获取年龄列表 SELECT *FROM Class_AWHERE age < ALL ( 22, 23, NULL )--2. 将 ALL 谓词等价改写为 AND SELECT *FROM Class_AWHERE (age < 22) AND (age < 23) AND (age < NULL);--3.对NULL使用“<”后,结果变为 unknown SELECT *FROM Class_AWHERE (age < 22) AND (age < 23) AND unknown;--4. 如果AND运算里包含unknown,则结果不为true SELECT *FROM Class_AWHERE false 或 unknown;

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

  • 极值函数在统计时会把为 NULL 的数据排除掉

  • 极值函数在输入为空表(空集)时会返回 NULL

ALL 谓词和极值函数表达的命题含义分别如下所示:

  • ALL 谓词:他的年龄比在东京住的所有学生都小
  • 极值函数:他的年龄比在东京住的年龄最小的学生还要小

命题不等价的情况:

  • 表里存在 NULL 时它们是不等价的

  • 谓词(或者函数)的输入为空集的情况(例如B表中没有学生住东京):

    这时,使用 ALL 谓词的 SQL 语句会查询到 A 班的所有学生。然而,用极值函数查询时一行数据都查询不到。因为极值函数在输入为空表(空集)时会返回 NULL

-- 查询比 B 班住在东京的年龄最小的学生还要小的 A 班学生
SELECT *
FROM Class_A
WHERE age < ( SELECT MIN(age)FROM Class_BWHERE city = '东京' );
-- 原理
--1. 极值函数返回 NULL
SELECT *
FROM Class_A
WHERE age < NULL;
--2.对NULL使用“<”后结果为 unknown
SELECT *
FROM Class_A
WHERE unknown;

比较对象原本就不存在时,根据业务需求有时需要返回所有行,有时需要返回空集。需要返回所有行时(感觉这类似于“不战而胜”),需要使 用 ALL 谓词,或者使用 COALESCE 函数将极值函数返回的 NULL 处理成合 适的值。

聚合函数和NULL

聚合函数在输入为空表(空集)时会返回 NULL

-- 查询比住在东京的学生的平均年龄还要小的 A 班学生的 SQL 语句?
SELECT *
FROM Class_A
WHERE age < ( SELECT AVG(age)FROM Class_BWHERE city = '东京' );
-- 没有住在东京的学生时,AVG 函数返回 NULL。

本节要点

  1. NULL 不是值。
  2. 因为 NULL 不是值,所以不能对其使用谓词。
  3. 对 NULL 使用谓词后的结果是 unknown
  4. unknown 参与到逻辑运算时,SQL 的运行会和预想的不一样。
  5. 按步骤追踪 SQL 的执行过程能有效应对 4 中的情况。

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

MICK-SQL进阶教程 1.3 三值逻辑和NULL相关推荐

  1. SQL进阶之路03:三值逻辑和NULL

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

  2. SQL三值逻辑和NULL

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

  3. 【SQL学习笔记】《SQL进阶教程》1.1

    SQL进阶教程学习笔记1.1 1-1case 表达式 将已有编号方式转换为新的方式并统计 SELECT CASE pref_nameWHEN '辽宁' THEN '东北'WHEN '福建' THEN ...

  4. 【SQL进阶教程】第一章 case表达式

    本系列基于<SQL进阶教程>(如下图)学习,实现了书中代码及练习题代码.PS:电子书请大家各自默默脚本之家. [知识点1]case表达式概述 Case表达式有简单case表达式和搜索cas ...

  5. SQL进阶教程—CASE表达式

    所有的文件在SQL进阶教程 (ituring.com.cn),随书下载那里 概述 文章原址 基本写法 简单CASE表达式 SELECT CASE 列名称WHEN 匹配字符 THEN 转换字符WHEN ...

  6. 【SAP Hana】X档案:SAP HANA SQL 进阶教程

    SAP HANA SQL 进阶教程 5.HANA SQL 进阶教程 (1)Databases (2)User & Role (3)Schemas (4)Tables (5)Table Inde ...

  7. SQL进阶教程—自链接的用法

    用法 https://moonshuo.cn/posts/14085.html 可重排列,排列,组合 需求:现在我需要将这个水果的品种各个组合起来,构成一个有序对的组合 在这个过程中首先执行完毕fro ...

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

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

  9. 读SQL进阶教程笔记14_SQL编程要点

    1. 消灭NULL 1.1. NULL惹人讨厌的原因 1.1.1. 进行SQL编码时,必须考虑违反人类直觉的三值逻辑 1.1.2. 指定IS NULL.IS NOT NULL的时候,不会用到索引,SQ ...

最新文章

  1. PHP面试中常见的字符串与文件操作题目
  2. 解决JRebel对myBatis Mapper 失效的问题
  3. java 网络传输中发送byte[]和接收到的不一致_为什么JAVA对象需要实现序列化?
  4. Java是先难后易吗_在解决问题的时候,是先难后易还是先易后难?
  5. MAC地址进行验证的方法
  6. 信息学奥赛一本通 1143:最长最短单词 | OpenJudge NOI 1.7 25
  7. POJ 3276 Face The Right Way 反转
  8. Bailian2687 数组逆序重放【逆序处理】
  9. 排序1+3:基数排序(RadixSort),希尔排序(ShellSort)和快速排序(QuickSort)
  10. Html+Js 3D 龙卷风
  11. 简单的Java代码实现斗地主
  12. 基于OpenCV的简单人流量统计
  13. 2022-Java面试宝典收藏版
  14. 2019最新楚琳web打印控件破解版|楚琳web打印控件下载
  15. 计算机怎么连接手机网络,电脑怎么连接手机的热点上网?
  16. xss.haozi练习通关详解
  17. 计算机中 空间局限性(Spatial Locality)与时间局限性(Temporal Locality)
  18. JAVA计算机毕业设计教育培训机构信息管理系统Mybatis+系统+数据库+调试部署
  19. 虚幻4场景渲染源码分析概述
  20. Js实现Base64编码、解码

热门文章

  1. 华夏时报:腾讯QQ如何监视你的?
  2. 前端 forward和redirect区别
  3. 世界杯前一周,京东啤酒销量环比增长175%!2022啤酒全年度数据总结
  4. c语言笔记:对a[i++]的理解
  5. 原生js实现移动端选择器插件 H5
  6. 微信小程序开发工具中如何创建与pages目录同级的目录
  7. eclipse2022.6版本新建maven项目时pom报错:Cannot find the declaration of element ‘project‘. pom.xml
  8. 三百内最好的蓝牙耳机有哪些?音质最好的百元蓝牙耳机推荐
  9. 深度学习中的几个错误率和准确率
  10. Oracle Golden Gate - 概念和机制(OGG)