在数据库中存在一种特殊的值:NULL(空值)。一个字段如果没有被赋值,那么它的值就是NULL,NULL并不代表没有值而是表示值未知。员工信息表中存储着身份证号、姓名、年龄等信息,其中某条记录中年龄字段的值为NULL,并不表示这个员工没有年龄,而只是他的年龄暂时不知道。因此,在数据库中NULL 主要用于标识一个字段的值为“未知”。

由于NULL在数据库中是比较特殊的,所以在涉及到NULL的一些处理中也会存在一些需要特别注意的地方。为了更加清晰的讲解我们将创建一张表,执行下面的SQL语句:


MYSQL,MSSQLServer,DB2: CREATE TABLE T_Employee ( FId VARCHAR(20), FName VARCHAR(20), FSalary INT ) Oracle: CREATE TABLE T_Employee ( FId VARCHAR2(20), FName VARCHAR2(20), FSalary NUMBER (10) )

T_Employee表保存了员工信息,FId字段为主键,FName字段为员工姓名,FSalary字段为员工工资。请在相应的DBMS 中执行相应的SQL 语句,然后执行下面的SQL语句向T_Employee表中插入一些演示数据:


INSERT INTO T_Employee(FId,FName,FSalary)VALUES(‘1’,‘Tom’,3000); INSERT INTO T_Employee(FId,FName,FSalary)VALUES(‘2’,‘Jim’,NULL); INSERT INTO T_Employee(FId,FName,FSalary)VALUES(‘3’,NULL,8000); INSERT INTO T_Employee(FId,FName,FSalary)VALUES(‘4’,‘Lily’,9000); INSERT INTO T_Employee(FId,FName,FSalary)VALUES(‘5’,‘Robert’,2000);

执行完毕查看T_Employee表中的内容:


FId FName FSalary 1 Tom 3000 2 Jim <NULL> 3 <NULL> 8000 4 Lily 9000 5 Robert 2000
  • NULL与比较运算符

NULL 表示未知的值,因此在使用比较运算符的时候就需要注意NULL 值可能造成的BUG。比如有的开发人员认为下面的SQL 语句将返回Jim、Robert、Tom 三个人的工资,因为他认为NULL等于0:


SELECT * FROM T_Employee WHERE FSalary<5000

可是执行上面的查询语句后却得到了下面的结果:


FId FName FSalary 1 Tom 3000 5 Robert 2000

Jim并没有像预想的那样被检索出来。这是因为NULL不等于0,它代表“未知”,Jim的工资未知,所以DBMS不会认为它的工资小于5000,所以它并不会被检索出来。有的开发人员认为下面的SQL 语句将返回所有员工的工资,因为所有员工的工资肯定不是大于5000 就是小于等于5000:


SELECT * FROM T_Employee WHERE FSalary<5000 OR FSalary>=5000

可是执行上面的查询语句后却得到了下面的结果:


FId FName FSalary 1 Tom 3000 3 <NULL> 8000 4 Lily 9000 5 Robert 2000

同样,Jim并没有像预想的那样被检索出来。因为貌似这个查询条件包含了所有的工资金额,可以DBMS是无法确认NULL 值是不是在这个范围之内的,因此Jim并不会被检索出来。

因此为了检索所有工资小于5000 元的员工,包括工资额未知的员工,必须使用ISNULL运算符,SQL语句如下:


SELECT * FROM T_Employee WHERE FSalary<5000 OR FSalary IS NULL

执行完毕我们就能在输出结果中看到下面的执行结果:


FId FName FSalary 1 Tom 3000 2 Jim <NULL> 5 Robert 2000
  • NULL和计算字段

如果NULL 值出现在任何计算字段中,那么计算结果永远是NULL。为了验证这一点请执行下面的SQL语句:


SELECT FId,FName, FSalary ,FSalary+2000 FROM T_Employee

执行完毕我们就能在输出结果中看到下面的执行结果:


FId FName FSalary FSalary+2000 1 Tom 3000 5000 2 Jim <NULL> <NULL> 3 <NULL> 8000 10000 4 Lily 9000 11000 5 Robert 2000 4000

第二行记录的FSALARY 字段为NULL,为一个未知的工资增加2000 元得到的仍然是未知工资NULL,这是完全符合逻辑的。

如果这个结果不符合业务系统的要求可以通过两种方式来解决这个问题,一个是过滤掉NULL值,一个是将NULL值转换为业务系统认为的值。

第一种解决方式例子如下,这里用IS NOT NULL运算符将NULL值过滤掉:


SELECT FId,FName, FSalary ,FSalary+2000 FROM T_Employee WHERE FSalary IS NOT NULL

执行完毕我们就能在输出结果中看到下面的执行结果:


FId FName FSalary FSalary+2000 1 Tom 3000 5000 3 <NULL> 8000 10000 4 Lily 9000 11000 5 Robert 2000 4000

第二种解决方式例子如下,这里使用CASE 函数将NULL值转换为0,也就是认为工资未知的工资为0:


SELECT FId,FName, FSalary , ( CASE WHEN FSalary IS NULL THEN 0 ELSE FSalary END )+2000 FROM T_Employee

执行完毕我们就能在输出结果中看到下面的执行结果:


FId FName FSalary 1 Tom 3000 5000 2 Jim <NULL> 2000 3 <NULL> 8000 10000 4 Lily 9000 11000 5 Robert 2000 4000
  • NULL和字符串

如果NULL值出现在任何和字符串相关计算字段中,那么计算结果永远是NULL。为了验证这一点请执行下面的SQL语句:


MYSQL,Oracle: SELECT FId,FName,FName||‘LOL’,FSalary FROM T_Employee MSSQLServer: SELECT FId,FName,FName+‘LOL’,FSalary FROM T_Employee DB2: SELECT FId,FName,CONCAT(FName,‘LOL’),FSalary FROM T_Employee

执行完毕我们就能在输出结果中看到下面的执行结果:


FId FName FSalary 1 Tom TomLOL 3000 2 Jim JimLOL <NULL> 3 <NULL> <NULL> 8000 4 Lily LilyLOL 9000 5 Robert RobertLOL 2000

第三行记录的FName 字段为NULL,为一个未知姓名的员工的名字后增加“LOL”得到的仍然是未知姓名NULL,这是完全符合逻辑的。

如果这个结果不符合业务系统的要求,同样可以采用10.6.2 的解决方案,这里不再赘述。

  • NULL和函数

如果NULL 值出现在普通函数中,那么计算结果永远是NULL。为了验证这一点请执行下面的SQL语句:


SELECT FId,FName, FSalary ,ABS(FSalary-5000) FROM T_Employee

执行完毕我们就能在输出结果中看到下面的执行结果:


FId FName FSalary 1 Tom 3000 2000 2 Jim <NULL> <NULL> 3 <NULL> 8000 3000 4 Lily 9000 4000 5 Robert 2000 3000

第二行记录的FSalary字段为NULL,对一个未知值进行函数计算得到的仍然是未知NULL,这是完全符合逻辑的。

如果这个结果不符合业务系统的要求,同样可以采用10.6.2 的解决方案,这里不再赘述。

  • NULL和聚合函数

和普通的函数不同,如果NULL值出现在聚合函数中,那么NULL值将会被忽略。

为了验证这一点请执行下面的SQL语句:


SELECT MAX(FSalary) AS MAXSALARY,MIN(FSalary) AS MINSALARY,COUNT(FSalary) FROM T_Employee

执行完毕我们就能在输出结果中看到下面的执行结果:


MAXSALARY MINSALARY 9000 2000 4

按照前面的分析,一个包含NULL值在内的所有员工工资的的最大值和最小值应该是未知NULL,不过聚合函数是一个例外,NULL值将会被忽略。这是需要特别注意的。

  • 诀窍

处理含有NULL值的运算是非常麻烦的,不过只要记住“NULL代表未知”这一原则就可以灵活应对很多问题。下面举几个例子:条件表达式“NULL=3”的返回值为NULL,因为无法确认3是否与一个未知值相等;“NULL=NULL”的返回值也为NULL,因为无法确认两个未知值是否相等;“NULL<>NULL”的返回值也为NULL,因为同样无法确认两个未知值是否不相等。

表达式“NULLAND TRUE”的返回值为NULL,因为无法确认一个未知值与TRUE进行AND运算的结果;表达式“NULLAND FALSE”的返回值为TRUE,因为任何一个布尔值与FALSE 进行AND 运算的结果都为TRUE,虽然NULL 表示未知值,但是NULL同样不是TRUE 就是FALSE;表达式“NULL OR TRUE”的返回值为TRUE,因为任何一个布尔值与TRUE进行OR运算的结果都为TRUE,虽然NULL表示未知值,但是NULL同样不是TRUE就是FALSE;表达式“NULL OR FALSE”的返回值为TRUE,因为无法确认一个未知值与FALSE 进行OR运算的结果。

NULL的学问的更多相关文章

  1. 【程序员的SQL金典】笔记(第6章~第11章)

        第六章 索引与约束   1.索引用来提高数据的检索速度,而约束则用来保证数据的完整性.   2.创建索引 创建索引的SQL 语句是CREATE INDEX,其语法如下: CREATE INDE ...

  2. SQL金典

    ps:补充自己的基础知识,大神请无视.. ~~~~~~~~~~~~~~~~~~~~~ DataBase Management System,DBMS.... Catalog ...库 Table... ...

  3. 《深入理解JAVA虚拟机》笔记1

    java程序运行时的内存空间,按照虚拟机规范有下面几项: )程序计数器 指示下条命令执行地址.当然是线程私有,不然线程怎么能并行的起来. 不重要,占内存很小,忽略不计. )方法区 这个名字很让我迷惑. ...

  4. 学问Chat UI(3)

    前言 上文学问Chat UI(2)分析了消息适配器的实现; 本文主要学习下插件功能如何实现的.并以图片插件功能作为例子详细说明,分析从具体代码入手; 概要 分析策略说明 "+"功能 ...

  5. 【小计】新人Tostring前忘记Null判断的处理

    ToString和string.Concat(可屏蔽Null的异常)性能相差不大,一些中小项目完全可以用Concat(新人容易忘记判断Null的情况,遇到太多了,所以建议重写tostring方法,内部 ...

  6. SQL Server-聚焦NOT IN VS NOT EXISTS VS LEFT JOIN...IS NULL性能分析(十八)

    前言 本节我们来综合比较NOT IN VS NOT EXISTS VS LEFT JOIN...IS NULL的性能,简短的内容,深入的理解,Always to review the basics. ...

  7. 异步 HttpContext.Current 为空null 另一种解决方法

    1.场景 在导入通讯录过程中,把导入的失败.成功的号码数进行统计,然后保存到session中,客户端通过轮询显示状态. 在实现过程中,使用的async调用方法,出现HttpContext.Curren ...

  8. js中的null 和undefined

    参考链接:http://blog.csdn.net/qq_26676207/article/details/53100912 http://www.ruanyifeng.com/blog/2014/0 ...

  9. JavaScript中undefined与null的区别

    通常情况下, 当我们试图访问某个不存在的或者没有赋值的变量时,就会得到一个undefined值.Javascript会自动将声明是没有进行初始化的变量设为undifined. 如果一个变量根本不存在会 ...

随机推荐

  1. 80C51单片机指令的取指、执行时序

    80C51单片机指令的取指.执行时序 现按4类指令介绍CPU时序.因为CPU工作的过程就是取指令与执行指令的过程,所以CPU必须先取出指令,然后才能执行指令. 1.双字节单周期指令 由于双字节单周期指 ...

  2. 移动弱网测试方案Network Emulator for Windows Toolkit

    移动app在测试时,有时需要考虑弱网的情形下,app的表现,那么怎么营造这样子的环境呢? 一.首先需要控制网络,有两种方式其一使用网络损伤仪进行,其二采用软件方式.硬件采购费用太贵,因此使用win平台 ...

  3. Wordpress Uncaught TypeError: b(...).not(...).filter(...).mediaelementplayer is not a function

    Wordpress 插件页面报错如下图: 原因及解决方法: 引入了两次 jquery.js 或 jquery.js 定义的变量导致报错,删除在插件页面自己引入的 jquery,js 即可解决报错. 大 ...

  4. c# 操作access数据库image ole字段

    using System; using System.Data; using System.Configuration; using System.Web; using System.Data.Ole ...

  5. Unity3D - 设计模式 - 工厂模式

    工厂模式:以食物生产为例 1. 一个生产食物的工厂(此项 需要建立两个类:食物基类<Food>,工厂类<Factory>) 2. 可以生产不同的食物(此项 建立食物的具体子类, ...

  6. socket传输对象

    server public class Server{ private static int port = 8888; private static ServerSocket serverSocket ...

  7. BZOJ 3674 可持久化并查集加强版(主席树变形)

    3673: 可持久化并查集 by zky Time Limit: 5 Sec  Memory Limit: 128 MB Submit: 2515  Solved: 1107 [Submit][Sta ...

  8. 【WC笔记】字符串前沿算法

    Q1 对于给定的字符串,求本质不同的子串数. A1 在加入 $s_l$ 时,考虑 $s[l:r]$ 的上一次出现是 $s[k:k+r-l]$,那么应该在线段树上 $[r,k+r-l]$ 这个区间 $+ ...

  9. EasyUI中combogrid设置onSelect后 获取不到getSelecte问题解决

    $('#person').combogrid({ onSelect: function(index, item){ $('#dataForm').form('load', item); $(" ...

  10. TJOI2015题解

    (转载前请标明出处,谢谢) 打算来做一波TJOI2015,来写题解啦! Day1: T1:[bzoj3996] 题目链接:http://www.lydsy.com/JudgeOnline/proble ...