查询反模式 - 正视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: ...
随机推荐
- qmake使用实践:包含动态库的Qt4工程
文章来源:http://blog.csdn.net/dbzhang800/article/details/6317006 本文是qmake的一个使用练习,是半年前所学的 分析与学习Qt Solutio ...
- Android Fragment getActivity返回null解决
在Android开发中,如果我们用到V4包里面的Fragment,在应用被切换到后台的时候,Activity可能被回收,但是创建的所有Fragment则会被保存到Bundle里面,下面是Fragmen ...
- 基本SQL练习题--选课经典例题
为管理岗位业务培训信息,建立3个表: S (S#,SN,SD,SA) S#,SN,SD,SA 分别代表学号.学员姓名.所属单位.学员年龄 C (C#,CN ) C#,CN 分别代表课程编号.课程名称 ...
- MVC4.0系统开发新手历程(四)数据列表查询
任何系统都不可避免的就是数据的查询展示,我觉得这里最值得一说的就是分部视图以及数据分页了 首先添加控制器 在控制其上面的名字为Index的Action上面右击,添加视图即可添加对应的视图,分部视图呈现 ...
- JFrame画图基础和事件监听
消息框 JOptionPane.showMessageDialog(mine.this, "删除不成功!"); 画图 class MyJPanel extends JPanel / ...
- jQuery旋转插件jqueryrotate 图片旋转
"jquery.rotate.min.js"是jQuery旋转rotate插件,支持Internet Explorer 6.0+ .Firefox 2.0 .Safari 3 .O ...
- hdu 3836 Equivalent Sets(tarjan+缩点)
Problem Description To prove two sets A and B are equivalent, we can first prove A is a subset of B, ...
- MVC MVC 路由详解
在项目中我们引用了System.Web.Routing; Routing的作用: 确定Controller 确定Action 确定其他参数 根据识别出来的数据, 将请求传递给Controller和 ...
- SecureCRT 安装及初始化配置
安装 SecureCRT 7.3.4 安装以及破解方法 SecureCRT 6.5.0 汉化解压版 初始化配置 这里配置以SecureCRT 6.5.0 汉化解压版为例 1.调整SecureCRT终端 ...
- [Node.js] Using ES6 and beyond with Node.js
If you're used to using all the latest ES6+ hotness on the front end via Babel, working in Node.js c ...