当前位置: 首页 > news >正文

= null 和 is null;SQL中关于NULL处理的4个陷阱;三值逻辑

一、概述

1、NULL参与的所有的比较和算术运算符(>,=,<,<>,<=,>=,+,-,*,/) 结果为unknown;

2、unknown的逻辑运算(AND、OR、NOT)遵循三值运算的真值表;

3、如果运算结果直接返回用户,使用NULL来标识unknown

4、如果运算结果是作为条件判断真假,那么需要通过三值逻辑进行运算,并最终通过以下映射逻辑确定整体判定

5、{false、unknown} -> false

6、{true} ->true

7、在UNION 或 INTERSECT等集合运算中,NULL 被视为彼此相等。

二、三值逻辑

在逻辑学中的三值逻辑(three-valued,也称为三元,或三价逻辑,有时缩写为3VL)是几个多值逻辑系统中的其中之一。有三种状态来表示真、假和一个表示不确定的第三值;这相对于基础的二元逻辑(比如布尔逻辑,它只提供真假两种状态)。

三值逻辑有三个真值(true、false、unknown),它的AND、OR、NOT运算的真值表如下:
在这里插入图片描述

三、SQL中关于NULL处理的4个陷阱

1、 比较谓词与NULL

null并不能判断表达式为空, 判断表达式为空应该使用is null
goods表有13条数据,其中13条数据的count字段的值是null

select *from goods --14条
错误写法:
select *from goods g where g.count = null --0条

正确写法:
select *from goods g where g.count is null --13条

错误原因:
原因是:g.count= null的结果是unknown;然后unknown判断真假为false。

g.count = null -> unknown -> false;

2、Case When与NULL

错误写法:
case expr when nulll then ‘值1’
并不能判断字段expr为null时, 给字段exper赋值为’值1’

正确写法:
case when expr is null then ‘值1’

select c_name, case when c_nationcode = ‘us’ then ‘USA’
when c_nationcode = ‘cn’ then ‘China’
when c_nationcode is null then ‘China’
else ‘Others’ end
from customer

3、 NOT IN 与NULL

NOT IN 子查询谓词,如果子查询结果集有空值,NOT IN谓词总为假 ,即sql不返回数据
例如goods表里数据的count字段只有1条数据是有值等于1,其余数据count字段值都是NULL。 worker表有9条数据,只有1条数据和goods表关联,worker.id = goods.count。

错误写法:
–查出0条
select *from worker where id not in (select count from goods)
因为使用NOT IN 时,子查询的结果集里有空值,这个SQL永远返回为空。

正确写法1:在子查询里加上非空限制
–查出8条
select *from worker where id not in (select count from goods where count is not null)

正确写法2:将NOT IN子查询改写为not exists子查询
–查出8条
select * from worker where not exists (select count from goods where count = worker.id)

4、修饰符ALL与NULL

ALL修饰的子查询谓词,如果子查询的结果集中有空值,则该谓词总为false。
假设通过下面的sql来获取订单系统关闭后注册的用户。
错误写法:
select * from customer where c_regdate > all(select o_orderdate from orders)

和上面的NOT IN类似的,由于子查询的结果中存在NULL,这个sql不会返回预期的结果。ALL 运算实际执行时也是与返回的结果集一一比较,然后进行AND的运算,最终结果unknown。而unknown作为条件进行评估是,结果为false.

正确写法1:在子查询里加上非空限制
select * from customer where c_regdate > all(select o_orderdate from orders where o_orderdate is not null)

正确写法2:
将expr > all或expr >= all改写为聚集函数 expr > (select max()…)(如果expr < all或expr <= all,则改写为expr < (select min() …)、
select * from customer where c_regdate > (select max(o_custkey) from orders)

–错误写法:0条
select *from worker where id > all (select count from goods)

–正确写法:8条
select *from worker where id > all (select count from goods where count is not null) --8条
select *from worker where id > all (select max(count) from goods) --8条

select *from worker where id <= all (select max(count) from goods) --1条

select *from worker where id <= all (select min(count) from goods) --1条
select *from worker where id > all (select min(count) from goods) --8条
注意:为了sql 优化不建议用聚集函数。
在这里插入图片描述
在这里插入图片描述

四、总结

1、NULL参与的所有的比较和算术运算符(>,=,<,<>,<=,>=,+,-,*,/) 结果为unknown
2、unknown的逻辑运算(AND、OR、NOT)遵循三值运算的真值表
3、如果运算结果直接返回用户,使用NULL来标识unknown
4、如果运算结果是作为条件判断真假,那么需要通过三值逻辑进行运算,并最终通过以下映射逻辑确定整体判定:
5、 {false、unknown} -> false
6、 {true} ->true

五、场景

接收到外部系统传的车辆配置编码保存在订单表的config_code字段里。在本系统订单表config_code 关联车辆配置表的编码字段code, 在车辆配置表查询内外饰颜色,选装等字段。如果外部系统传的车辆配置编码是空值,那么保存在订单表里的这条数据的config_code字段值也是空。用这条订单数据去关联车辆配置表,就什么也查不出来了。不会报错。

例如:
– goods表和worker表关联,w.id = g.count
–goods表14条数据,13条数据的count字段值为null, 1条数据的count = 1
–worker表9条数据, 数据的id字段值都正常
– 查询结果14条 = goods表和worker表关联的数据量1条 + goods表和worker表没关联的数据量13条
– 查询结果的总数据量=从表关联上主表的数据量+主表没关联上从表的数据量
select g.“name”,g.count ,w.work_number,w.id as wid from
goods g
left join worker w on w.id = g.count

在这里插入图片描述

参考文章:https://zhuanlan.zhihu.com/p/560941002

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • VulnHub:insomnia
  • 如何确定企业信息系统的安全保护等级
  • linux内核中list的基本用法
  • ELK日志分析系统部署文档
  • Memcached开发(八):使用PHP进行操作
  • Websocket自动消息回复服务端工具
  • elementUI在手机端使用遇到的问题总结
  • 计算机视觉发展历程
  • docker compose 容器 编排分组
  • 基于python深度学习遥感影像地物分类与目标识别、分割实践技术应用
  • Uniapp鸿蒙项目实战
  • PostgreSQL 中如何解决因大量并发删除和插入操作导致的索引抖动?
  • 用C语言写的一个扫雷小游戏
  • Composition API实现逻辑复用
  • ​探讨元宇宙和VR虚拟现实之间的区别​
  • 分享的文章《人生如棋》
  • 《用数据讲故事》作者Cole N. Knaflic:消除一切无效的图表
  • Android开发 - 掌握ConstraintLayout(四)创建基本约束
  • axios请求、和返回数据拦截,统一请求报错提示_012
  • IP路由与转发
  • JS基础之数据类型、对象、原型、原型链、继承
  • Odoo domain写法及运用
  • Python利用正则抓取网页内容保存到本地
  • Quartz实现数据同步 | 从0开始构建SpringCloud微服务(3)
  • react 代码优化(一) ——事件处理
  • Spring Boot MyBatis配置多种数据库
  • springboot_database项目介绍
  • Swoft 源码剖析 - 代码自动更新机制
  • Synchronized 关键字使用、底层原理、JDK1.6 之后的底层优化以及 和ReenTrantLock 的对比...
  • uva 10370 Above Average
  • 动手做个聊天室,前端工程师百无聊赖的人生
  • 你不可错过的前端面试题(一)
  • 如何选择开源的机器学习框架?
  • 通过git安装npm私有模块
  • Redis4.x新特性 -- 萌萌的MEMORY DOCTOR
  • ​ 全球云科技基础设施:亚马逊云科技的海外服务器网络如何演进
  • ​软考-高级-信息系统项目管理师教程 第四版【第23章-组织通用管理-思维导图】​
  • # .NET Framework中使用命名管道进行进程间通信
  • # SpringBoot 如何让指定的Bean先加载
  • $分析了六十多年间100万字的政府工作报告,我看到了这样的变迁
  • (delphi11最新学习资料) Object Pascal 学习笔记---第13章第6节 (嵌套的Finally代码块)
  • (Matalb时序预测)WOA-BP鲸鱼算法优化BP神经网络的多维时序回归预测
  • (搬运以学习)flask 上下文的实现
  • (备忘)Java Map 遍历
  • (蓝桥杯每日一题)love
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • (一)python发送HTTP 请求的两种方式(get和post )
  • (一)硬件制作--从零开始自制linux掌上电脑(F1C200S) <嵌入式项目>
  • (译)计算距离、方位和更多经纬度之间的点
  • (转)菜鸟学数据库(三)——存储过程
  • (转)使用VMware vSphere标准交换机设置网络连接
  • .mat 文件的加载与创建 矩阵变图像? ∈ Matlab 使用笔记
  • .NET BackgroundWorker
  • .NET C#版本和.NET版本以及VS版本的对应关系
  • .NET Core 中的路径问题