写点什么

如何正确理解 SQL 中的 NULL

  • 2020-04-01
  • 本文字数:1811 字

    阅读完需:约 6 分钟

如何正确理解SQL中的NULL

在查询数据库时,如果你想知道一个列是否为 NULL,SQL 查询语句该怎么写呢?


是不是这样:


SELECT * FROM SOME_TABLEWHERE SOME_COLUMN = NULL
复制代码


或者这样写:


SELECT * FROM SOME_TABLEWHERE SOME_COLUMN IS NULL
复制代码


正确的写法应该是第二种(WHERE SOME_COLUMN IS NULL)。


为什么要这样写?


在进行数据库数据比较操作时,我们不会使用“IS”关键词,不是吗?


例如,如果我们想要知道一个列的值是否等于 1,WHERE 语句是这样的:


WHERE SOME_COLUMN = 1
复制代码


那为什么 NULL 值要用 IS 关键字呢?为什么要以这种方式来处理 NULL?


因为,在 SQL 中,NULL 表示“未知”。也就是说,NULL 值表示的是“未知”的值。

NULL 等于未知

在大多数数据库中,NULl 和空字符串是有区别的。


但并不是所有数据库都这样,例如,Oracle 就不支持空字符串,它会把空字符串自动转成 NULL 值。


在其他大多数数据库里,NULL 值和字符串的处理方式是不一样的:


  • 空字符串表示“没有值”,这个值是已知的。

  • NULL 表示“未知值”,这个值是未知的。


这就好比我问了一个问题:“美国总统罗斯福的中间名是什么”?


  • 可能有人会回答说:“我不知道罗斯福总统的中间名是什么”。对于这种情况,可以在数据库中使用 MIDDLE_NAME 列来表示罗斯福的中间名,而这一列的值为 NULL。

  • 也可能有人会回答说:“罗斯福总统没有中间名。他的父母没有给他取中间名,所以我知道罗斯福总统确实没有中间名”。对于这种情况,MIDDLE_NAME 列应该是一个空字符串。


Oracle 比较特殊,两个值都使用 NULL 来表示,而其他大多数数据库会区分对待。


但只要记住 NULL 表示的是一个未知的值,那么在写 SQL 查询语句时就会得心应手。


例如,如果你有一个这样的查询语句:


SELECT * FROM SOME_TABLEWHERE 1 = 1
复制代码


这个查询会返回所有的行(假设 SOME_TABLE 不是空表),因为表达式“1=1”一定为 true。


如果我这样写:


SELECT * FROM SOME_TABLEWHERE 1 = 0
复制代码


表达式“1=0”是 false,这个查询语句不会返回任何数据。


但如果我写成这样:


SELECT * FROM SOME_TABLEWHERE 1 = NULL
复制代码


这个时候,数据库不知道这两个值(1 和 NULL)是否相等,所以它也不会返回任何数据。

三元逻辑

SQL 查询语句中的 WHERE 一般会有三种结果:


  • 它可以是 true(这个时候会返回数据);

  • 它可以是 false(这个时候不会返回数据);

  • 它也可以是 NULL 或未知(这个时候也不会返回数据)。


你可能会想:“既然这样,那我为什么要去关心是 false 还是 NULL?它们不是都不会返回数据吗?”


接下来,我来告诉你在哪些情况下会有问题:我们来看看 NOT()。


假设有这样的一个查询语句:


SELECT * FROM SOME_TABLEWHERE NOT(1 = 1)
复制代码


数据库首先会计算 1=1,这个显然是 true。


接着,数据库会应用 NOT() 条件,所以 WHERE 返回 false。


所以,上面的查询不会返回任何数据。


但如果把语句改成这样:


SELECT * FROM SOME_TABLEWHERE NOT(1 = 0)
复制代码


数据库首先会计算 1=0,这个肯定是 false。


接着,数据库应用 NOT() 条件,这样就得到相反的结果,变成了 true。


所以,这个语句会返回数据。


但如果把语句再改成下面这样呢?


SELECT * FROM SOME_TABLEWHERE NOT(1 = NULL)
复制代码


数据库首先计算 1=NULL,它不知道 1 是否等于 NULL,因为它不知道 NULL 的值是什么。


所以,这个计算不会返回 true,也不会返回 false,它会返回一个 NULL。


接下来,NOT() 会继续解析上一个计算返回的结果。


当 NOT() 遇到 NULL,它会生成另一个 NULL。未知的相反面是另一个未知。


所以,对于这两个查询:


SELECT * FROM SOME_TABLEWHERE NOT(1 = NULL)
复制代码



SELECT * FROM SOME_TABLEWHERE 1 = NULL
复制代码


都不会返回数据,尽管它们是完全相反的。

NULL 和 NOT IN

如果我有这样的一个查询语句:


SELECT * FROM SOME_TABLEWHERE 1 IN (1, 2, 3, 4, NULL)
复制代码


很显然,WHERE 返回 true,这个语句将返回数据,因为 1 在括号列表里是存在的。


但如果这么写:


SELECT * FROM SOME_TABLEWHERE 1 NOT IN (1, 2, 3, 4, NULL)
复制代码


很显然,WHERE 返回 false,这个查询不会返回数据,因为 1 在括号列表里存在,但我们说的是“NOT IN”。


但如果我们把语句改成这样呢?


SELECT * FROM SOME_TABLEWHERE 5 NOT IN (1, 2, 3, 4, NULL)
复制代码


这里的 WHRE 不会返回数据,因为它的结果不是 true。数字 5 在括号列表里可能不存在,也可能存在,因为当中有一个 NULL 值(数据库不知道 NULL 的值是什么)。


这个 WHERE 会返回 NULL,所以整个查询不会返回任何数据。


希望你们现在都清楚该怎么在 SQL 语句中处理 NULL 值了。

英文原文

Null Values in SQL Queries


2020-04-01 14:152661
用户头像
小智 让所有人认同的文字称不上表达

发布了 408 篇内容, 共 399.6 次阅读, 收获喜欢 1985 次。

关注

评论 1 条评论

发布
用户头像
涨姿势了,以前确实没有好好思考过null的问题
2020-04-01 23:44
回复
没有更多了
发现更多内容

四个小时的轮番轰炸,三面蚂蚁金服,拿到offer的那天我的眼泪止不住的流了下来!

钟奕礼

Java 程序员 架构 后端 java面试

美团前端面试题(附答案)

hellocoder2029

JavaScript 前端

关于Linux网络与网络编程

Joseph295

从程序员的视角看待Linux操作系统

Joseph295

一文带你深入掌握ES6 Proxy数据代理

海底烧烤店ai

JavaScript node.js 全栈开发 9月月更

安全工作杂想 - 2022.9.12

心在飞

构建自动化运维体系的三大层级

穿过生命散发芬芳

自动化运维 9月月更

【SSM】Mybatis系列——mybatis的简介、环境搭建、CRUD操作

胖虎不秃头

mybatis SSM框架 9月月更

分布式系统的一致性算法导论

Joseph295

关于 HBase

Joseph295

图灵访谈 | 一位半路出家的程序员的“天命”之选

图灵社区

Java 人工智能 大数据 编程语言 可视化

GitHub上标星90k+的《Java知识总结+面试指南》到底有什么魅力?

钟奕礼

Java 程序员 架构 后端 java面试

下载量已过亿次!阿里内部不外传秘籍50万字Java面试手册首次开放

钟奕礼

Java 程序员 架构 后端 java面试

【SSM】Mybatis系列——配置解析

胖虎不秃头

mybatis ssm 9月月更

面试突击82:SpringBoot 中如何操作事务?

王磊

Java 面试题

2022-09-12:以下go语言代码输出什么?A:true;B:false;C:无法编译;D:运行时 panic。 package main func main() { var x chan<-

福大大架构师每日一题

golang 福大大 选择题

关于 Java Stream 以及lambda

Joseph295

图灵访谈 | 一位半路出家的程序员的“天命”之选

图灵教育

Java 人工智能 大数据 编程语言 可视化

到底什么才是完美的回答:什么是事务?

Joseph295

Flink精粹:可能是关于Flink知识点最密集的文章

Joseph295

网络协议中链接与断开的握手有何区别?

想要飞的猪

三次握手 网络协议、 TCP四次挥手

常见的主要监控数据获取方式

阿泽🧸

监控 9月月更

滴滴前端面试题合集

coder2028

JavaScript 前端

质量问题不是不爆,时候未到

Java 架构 职场

Java 并发:这是你需要的最后一篇文章

Joseph295

Kubernetes: 关于云原生,我知道的一切都在这里了

Joseph295

关于SpringCloudAlibaba,看阿里这篇笔记真香

程序知音

Java 微服务 阿里 SpringCloud 后端技术

【C语言深度剖析】深入理解C语言中的移位操作符(代码+图解)

Albert Edison

C语言 9月月更 左移操作符 右移操作符

应届的我,面试37次,16个offer上岸后总结了一些面试心得

收到请回复

Java 项目管理 面试 语言 & 开发 秋招

C++学习---变长参数(stdarg.h)的实现原理

桑榆

c++ 源码阅读 9月月更

【SSM】Mybatis系列——解决属性名和字段名不一致的问题、日志

胖虎不秃头

mybatis SSM框架 9月月更

如何正确理解SQL中的NULL_数据库_MITCHUM_InfoQ精选文章