查询反模式 - 正视NULL值
一、提出问题
不可避免地,我们都数据库总有一些字段是没有值的。不管是插入一个不完整的行,还是有些列可以合法地拥有一些无效值。SQL 支持一个特殊的空值,就是NULL。
在很多时候,NULL值导致我们的程序出现报错的现象,于是很多人就开始拒绝NULL值,想各种各样的方法来避免使用NULL值,但是很遗憾,NULL值恰恰就是满足我们的需要用于表示空值的。
空值经常存在于我们的数据库当中:
- 例如一个在职员工的离职时间。
- 例如一辆电力驱动的车的燃油消耗比。
二、反模式
很多人对于NULL值感觉到恐惧,原因在于不知道什么时候就会因为一个NULL冒出一个报错。实际上都是由于对NULL值的理解有误引起的。很多人将NULL值当做一个0、False、空字符串来理解。实际上SQL将NULL当做一个特殊的值,并不同于0、false、空字符串。
实际上对NULL值最好的理解是“不知道”。用“不知道”可以正确理解与NULL值的运算,如"+","-",AND,OR,NOT等。
我们来看看容易出错的地方。
首先,我们建一张表如下:

在里面添加几条数据:

注意里面的NULL值。
我们,来看看如下SQL语句的结果:

以上可以理解为:不知道+10=不知道

留意到上面的数据少了一条,Age为NULL的那一条,原因在于NOT (NULL)的值并不为True也并不为False而是NULL。
以上的例子还有很多,于是就出现了很多人引用一个普通的值来代替NULL值,例如"无效"、"未知"或者-1。假设我们使用的是-1,虽然我们在使用
SELECT * FROM Person WHERE Age <> -1
作为查询条件,看起来没什么问题,但是这时候当我们使用SUM、AVG等聚合函数的时候就会导致计算结果出错。
使用NULL并不是反模式,反模式是将NULL作为一个普通值处理或者使用一个普通的值来取代NULL的作用。
三、解决方案 - 将NULL视为特殊值
下面先列举一些程序员运用NULL运算时期望得到的结果与实际结果。
1、在标量表达式中使用NULL
| 表达式 | 期望值 | 实际值 | 原因 |
| NULL=0 | TRUE | NULL | NULL不是0 |
| NULL=12345 | FALSE | NULL | 未指定值不知道是否等于所给值 |
| NULL<>12345 | TRUE | NULL | 未指定值也不知道一定不等于所给值 |
| NULL+12345 | 12345 | NULL | NULL不是0 |
| NULL||'string' | 'string' | NULL | NULL不是空字符串 |
| NULL=NULL | TRUE | NULL | 两个都不知道,鬼知道你等不等 |
| NULL!=NULL | FALSE | NULL | 两个都不知道,贵知道你等不等 |
2、在布尔表达式中使用NULL
| 表达式 | 期望值 | 实际值 | 原因 |
| NULL AND TRUE | FALSE | NULL | NULL不是FALSE |
| NULL AND FALSE | FALSE | FALSE | FALSE AND 什么都是FALSE |
| NULL OR FALSE | FALSE | NULL | NULL不是FALSE |
| NULL OR TRUE | TRUE | TRUE | TRUE OR 什么都是TRUE |
| NOT (NULL) | TRUE | NULL | NULL 不是FALSE |
3、检索NULL值
由于=NULL或者不等于NULL操作在对NULL进行比较时都是返回NULL,因此在检索NULL的时候,要用写特别操作:
IS NULL 和 IS NOT NULL
对于上面的例子,如果我们希望检索NULL,可以这样写:

4、声明NOT NULL列
如果NULL会破坏程序结构或者NULL本身就是毫无意义的,那么最好就在定义列时加上NOT NULL约束。让数据库来帮你确保约束的实行比自己写代码可靠得多。
有人建议为每一列都定义一个DEFAULT值,这样一来当在执行插入操作时,即使省略了某一列,也能获得一个非NULL值。这样的建议也并不是通用的。就假设有一个年龄列,设置了一个Default值为0,那么使用AVG聚合函数的时候结算的是错误的结果。NULL值是不被纳入AVG的计算范畴之内的,而0会被计算。

如对于上表:

而,如果我们将最后两行设置为0,那么AVG的结果将是:

5、动态默认值
动态默认值这个东西的意思是,当我们的查询碰到一个NULL值的时候,我们希望它返回一个非NULL的默认值,已不至于计算出错。
比如 姓 + NULL + 名返回的是NULL。
因此,我们不希望中间返回NULL,而是''空字符串。这样计算才正常。
大部分数据库都提供了一个COALESCE函数实现这个功能,来看SQLServer中的示例:
我们将第一行的姓名置NULL

查询反模式 - 正视NULL值的更多相关文章
- 针对多条件查询,应对 url 无用 null 值现象处理
多条件查询 应对 url 无用 null 值现象 处理例如:http://xxoo.b2b.com/orders?city_id=5&repertory_id=7&area_id=39 ...
- linq 在查询表达式中处理 null 值
此示例显示如何在源集合中处理可能的 null 值. IEnumerable<T> 等对象集合可包含值为 null 的元素. 如果源集合为 null 或包含值为 null 的元素,并且查询不 ...
- 查询反模式 - GroupBy、HAVING的理解
为了最简单地说明问题,我特地设计了一张这样的表. 一.GROUP BY单值规则 规则1:单值规则,跟在SELECT后面的列表,对于每个分组来说,必须返回且仅仅返回一个值. 典型的表现就是跟在SELEC ...
- 查询反模式 - GroupBy和HAVING的理解
为了最简单地说明问题,我特地设计了一张这样的表. 一.GROUP BY单值规则 规则1:单值规则,跟在SELECT后面的列表,对于每个分组来说,必须返回且仅仅返回一个值. 典型的表现就是跟在SELEC ...
- LINQ查询表达式(5) - LINQ Null值处理&异常处理
查询表达式中处理Null值 此示例演示如何处理源集合中可能的 null 值. 诸如 IEnumerable<T> 等对象集合可能包含值为 null 的元素. 如果源集合为 null 或包含 ...
- SQL反模式学习笔记1 开篇
什么是“反模式” 反模式是一种试图解决问题的方法,但通常会同时引发别的问题. 反模式分类 (1)逻辑数据库设计反模式 在开始编码之前,需要决定数据库中存储什么信息以及最佳的数据组织方式和内在关联方式. ...
- 为什么说JAVA中要慎重使用继承 C# 语言历史版本特性(C# 1.0到C# 8.0汇总) SQL Server事务 事务日志 SQL Server 锁详解 软件架构之 23种设计模式 Oracle与Sqlserver:Order by NULL值介绍 asp.net MVC漏油配置总结
为什么说JAVA中要慎重使用继承 这篇文章的主题并非鼓励不使用继承,而是仅从使用继承带来的问题出发,讨论继承机制不太好的地方,从而在使用时慎重选择,避开可能遇到的坑. JAVA中使用到继承就会有两 ...
- Oracle与Sqlserver:Order by NULL值介绍
针对页面传参到in的子集中去进行查询操作的话,就会有in(xxx,null),这样就会导致查询的结果中其实直接过滤掉了null,根本就查不出来null的值.之前对于null的操作都是进行不同数据库的n ...
- SQL反模式学习笔记14 关于Null值的使用
目标:辨别并使用Null值 反模式:将Null值作为普通的值,反之亦然 1.在表达式中使用Null: Null值与空字符串是不一样的,Null值参与任何的加.减.乘.除等其他运算,结果都是Null: ...
随机推荐
- 【转】Ubuntu重装,直接进win7,不进linux的解决方案(添加Ubuntu启动菜单)
原文网址:http://my.oschina.net/u/1377657/blog/281875 本人重装了Ubuntu12.04.4 LTS, 将Ubuntu启动项放在了/boot分区里面,启动的时 ...
- 数字积分法DDA(DDA(Digital Differential Analyzer)
数字积分法DDA(DDA(Digital Differential Analyzer) 数字积分法又称数字微分分析法DDA(Digital differential Analyzer),是在数字 ...
- Android ExpandableListActivity的简单介绍及小例子
Android中常常要用到ListView,但也经常要用到ExpandableListView,ListView是显示列表,而ExpandableListView显示的是分类的列表: 下面用一个例子来 ...
- HDU---4417Super Mario 树状数组 离线操作
题意:给定 n个数,查询 位置L R内 小于x的数有多少个. 对于某一次查询 把所有比x小的数 ”的位置“ 都加入到树状数组中,然后sum(R)-sum(L-1)就是答案,q次查询就要离线操作了,按高 ...
- ubuntu14.04 + cocos2d-x-2.2.6 + eclipse发布android + Qt Creator4
先把需要的东西准备好,打开控制台,执行以下语句: sudo apt--jdk lib32z1 lib32ncurses5 lib32bz2- 接下来,准备好cocos2d-x-2.2.6和 andro ...
- 如何在android上去控制开发进度
这次android的壁纸软件1.0版本终于可以上线了,软件的功能基本上实现了,但是用户体验不太好.在整个开发阶段和测试阶段,出现了很多预料之外的事情,比如size是1M多的json文件解析.高清图片导 ...
- [Javascript] Task queue & Event loop.
Javascript with Chorme v8 engine works like this : For Chorme engine, v8, it has call stack. And all ...
- 为iPhone6设计自适应布局(二)
Size Classes 自适应布局的布局约束自然是好东西,但也不是万能的,有时候我们也需要使用最基本的布局,所以使用size classes将它们两者结合起来才能碰撞出更有激情的火花. 引用我上篇译 ...
- oracle插入例子
string sql = "insert into EMST_JC_SBXX(XL,SBBM,SBWH,SBMC,CCBM,XNCS,CZXL,ZL,GL,ZZCJ,TCRQ,SYQX,XH ...
- Java数据结构漫谈-LinkedList
同样是List的数据结构,LinkedList是使用了前后指针,指明节点的方式来表示链表的,这与之前介绍的ArrayList http://www.cnblogs.com/yakovchang/p/j ...