不再迷惑,无值和NULL值
在关系型数据库的世界中,无值和NULL值的区别是什么?一直被这个问题困扰着,甚至在写TSQL脚本时,战战兢兢,如履薄冰,害怕因为自己的一知半解,挖了坑,贻害后来人,于是,本着上下求索,不达通幽不罢休的决心(开个玩笑),遂有此文。
学习过关系型数据库的伙伴都知道,NULL是指不确定的值,在数据库中绝对是噩梦的存在;而空值,一般对字符串类型而言,指没有任何值的字符串类型,为字符类型的变量设置为空值:set @vs='',空值跟无值不同。有人可能会问,无值是什么?无值,是指数据表中没有任何数据。无值和不确定值,单从字面意思上来看,两者之间的定义很清楚,一旦深究,这两者之间的关系,有时令人十分迷惑(confused),这是因为,在特定条件下,无值会转换为NULL值。
一,举个栗子,理解无值和NULL值的区别
比如,创建一个临时表,在不插入任何数据时,该数据表是空的,没有任何值,对其执行select命令,将不会返回任何数据值:
create table #temp
(
id int null
)
创建一个标量类型的变量,在不初始化时,该变量的值是不确定的,其值是NULL:
declare @vs int
创建一个表类型变量,在不初始化时,该表变量没有任何数据,是无值的:
declare @vt as table
(
id int null
)
总结一下,声明一个标量型变量,如果没有对变量进行初始化,其值是不确定的,是NULL值;对于表变量,临时表和基础表,如果没有插入任何数据,该表没有任何数据,是无值的。
二,无值和NULL值的转换
在开始本节之前,先为变量赋值,简单的一个select命令就可以完成变量的赋值:
select @vs=1
有些朋友思维比较活跃,立马会想到:“用select命令可以从表中取值为变量赋值”,对,但是,赋值方法不是我求索的重点,我关注的是从表中取值为变量赋值的结果。
1,从空表中为变量赋值
如果数据表是空表,没有任何值,那么数据库引擎不会执行赋值语句,变量保持原有值不变:
select @vs=id
from #temp
但是,如果采用以下方式,那么数据库引擎会执行赋值语句,由于空表不返回任何值,数据库引擎会把无值转换为不确定值NULL:
select @vs=(select top 1 id
from #temp)
诧异吗?无值和NULL值的转换,居然从不起眼的变量赋值开始。注意,当不返回任何值时,数据库引擎不确定返回值,就把无值转换为NULL值。
2,从空表中计算聚合
空表是没有任何数据的表,计算聚合会产生怎样的结果?
select count(0) as count_all
,count(id) as count_id
,max(id) as max_id
,min(id) as min_id
,avg(id) as avg_id
,sum(id) as sum_id
from #temp
当统计数据行数时,返回的是0;当计算聚合函数(max,min,avg和sum)的聚合值时,由于无值可以聚合,数据库引擎不能确定这些聚合函数的返回值,因此,数据库引擎返回NULL值。

三,聚合函数忽略NULL值
一般情况下,除了count(0),count(*)之外,聚合函数都会忽略NULL值,而统计非NULL值,如果读者有疑问,可以查看我的博客《TSQL 聚合函数忽略NULL值》。如果只知聚合函数忽略NULL值,而不知空表也会产生结果为NULL的聚合值,轻易得出聚合函数不会返回NULL值的定论,那就很尴尬。楼主曾遇到过一次“意外”,在一次调试脚本代码的过程中,我遇到max聚合函数返回NULL值的情况,当时一脸懵逼,直接怀疑自己之前的所学。
当聚合列值都是NULL值时,由于聚合函数忽略NULL值,因此,当计算聚合函数(max,min,avg和sum)的聚合值时,由于无值可以聚合,数据库引擎不能确定这些聚合函数的返回值,因此,数据库引擎返回NULL值。
insert into #temp(id)
values(null) select count(0) as count_all
,count(id) as count_id
,max(id) as max_id
,min(id) as min_id
,avg(id) as avg_id
,sum(id) as sum_id
from #temp
聚合函数(max,min,sum,avg和count)忽略null值,但不代表聚合函数不返回null值:如果数据表为空表,或聚合列值都是null,那么max,min,sum,avg聚合函数返回null值,而count 聚合函数返回0。聚合函数的共性:Null values are ignored。

不再迷惑:当不返回任何值时,数据库引擎不确定返回值,就把无值转换为NULL值。
附:select和set通过查询(query)对变量赋值的差异:
差异1:set 只能对变量赋值一次,而select 可以对变量赋值多次,变量值是最后一次赋值的结果
set @variable=(select top 1 column_name from data_table) select @variable=column_name
from data_table
差异2:如果查询(query)不返回任何值,set把变量的值设置为NULL,而select将不会执行赋值操作,变量保持原来的值不变
--if query returns no value, assign variable null
set/select @variable=(select top 1 column_name from data_table) --if query returns no value , the variable keeps previous value
select @variable=column_name
from data_table
代码中,查询(query)返回标量值,使用set和select对变量赋值,变量的值都是NULL
不再迷惑,无值和NULL值的更多相关文章
- 不再迷惑,无值和NULL值的转换
在关系型数据库的世界中,无值和NULL值的区别是什么?一直被这个问题困扰着,甚至在写TSQL脚本时,心有戚戚焉,害怕因为自己的一知半解,挖了坑,贻害后来人,于是,本着上下求索,不达通幽不罢休的决心(开 ...
- 为什么说JAVA中要慎重使用继承 C# 语言历史版本特性(C# 1.0到C# 8.0汇总) SQL Server事务 事务日志 SQL Server 锁详解 软件架构之 23种设计模式 Oracle与Sqlserver:Order by NULL值介绍 asp.net MVC漏油配置总结
为什么说JAVA中要慎重使用继承 这篇文章的主题并非鼓励不使用继承,而是仅从使用继承带来的问题出发,讨论继承机制不太好的地方,从而在使用时慎重选择,避开可能遇到的坑. JAVA中使用到继承就会有两 ...
- 【温故而知新-Javascript】比较 undefined 和 null 值
JavaScript 中有两个特数值: undefined和null,在比较它们的时候需要留心.在读取未赋值的变量或试图读取对象没有的属性时得到的就是 undefined 值. <!DOCTYP ...
- Oracle与Sqlserver:Order by NULL值介绍
针对页面传参到in的子集中去进行查询操作的话,就会有in(xxx,null),这样就会导致查询的结果中其实直接过滤掉了null,根本就查不出来null的值.之前对于null的操作都是进行不同数据库的n ...
- 【Javascript 基础】比较 undefined 和 null 值
JavaScript 中有两个特数值: undefined和null,在比较它们的时候需要留心.在读取未赋值的变量或试图读取对象没有的属性时得到的就是 undefined 值. <!DOCTYP ...
- oracle 中的round()函数、null值,rownum
round()函数:四舍五入函数 传回一个数值,该数值按照指定精度进行四舍五入运算的结果. 语法:round(number[,decimals]) Number:待处理的函数 Decimals:精度, ...
- GROUP BY 與 Null 值
若群組資料行包含了 Null 值,該資料列將變成結果中的一個群組.若群組資料行內包含了多個 Null 值,Null 值將放入單一群組內.此行為定義於 SQL-2003 標準之中. Product 資料 ...
- [改善Java代码]提防包装类型的null值
建议26: 提防包装类型的null值 我们知道Java引入包装类型(Wrapper Types)是为了解决基本类型的实例化问题,以便让一个基本类型也能参与到面向对象的编程世界中.而在Java 5中泛型 ...
- Javascript中null值,特别注意的两点
null 是一个javascript字面量,表示空值,就是没有对象被呈现.他是javascript原始值之一.null值常被放在期望一个对象上,但是不引用任何对象的参数位置,也就是说对象的初始化. 我 ...
随机推荐
- pyhon类继承
1,python类的继承 class A(object): name ='eason' age = '22' def __init__(self): print '我是A的构造函数!!!' def g ...
- leveldb源码分析--BloomFilter
bloomfilter是leveldb中的一大性能利器,所以为了文章的表现完整性这里新启这么一篇文章.leveldb中的bloomfilter的实现在bloom.cc中,是一个较为简单的实现,所以就不 ...
- css继承属性与非继承属性
一.无继承性的属性 1.display:规定元素应该生成的框的类型 2.文本属性: vertical-align:垂直文本对齐 text-decoration:规定添加到文本的装饰 text-shad ...
- C语言的历史及个人拙见
C语言是一个无限广阔的世界,你刚开始睁眼看它的时候以为视线的尽头就是边界,但当你慢慢走去,才发现天外有天.这或许就是江湖传说只有C才有真正高手的原因,或许我们也可以反过来说:C没有高手——因为没有人能 ...
- 【redis】redis的雪崩和穿透
1.什么是缓存穿透 一般的缓存系统,都是按照key值去缓存查询,如果不存在对应的value,就应该去DB中查找 .这个时候,如果请求的并发量很大,就会对后端的DB系统造成很大的压力.这就叫做缓存穿透. ...
- 新人如何进入IT行业
你遇到了我刚毕业时遇到的问题. 现在需要知道你希望在那里就业,上海和北京就业的待遇差不多,北京能比上海稍微少点(我是指你这类刚毕业的) 说主题好了 应届毕业,找工作都很难的,因为现在很多企业是不愿意找 ...
- ConstraintLayout使用手册
1. 解决痛点 主要用拖拽 解决嵌套过多 2. 简易使用手册 增加约束 四个角直接拖拽就好了 删除约束 match_constraint 属性 这个属性类似于match_parent,去掉margin ...
- SDN 第四次上机作业
1.建立以下拓扑,并连接上ODL控制器. 2.利用ODL下发流表,使得h3在10s内ping不通h1,10s后恢复. 3.借助Postman通过ODL的北向接口下发流表,再利用ODL北向接口查看已下发 ...
- saltstack二次开发(二)
Saltstack的api Salt-api有两种方式,一种是函数的形式,有人家定义好的函数,我们可以直接调用,直接写python代码调用函数或者类就可以了.第二种形式是salt-api有封装好的ht ...
- Spark项目之电商用户行为分析大数据平台之(六)用户访问session分析模块介绍
一.对用户访问session进行分析 1.可以根据使用者指定的某些条件,筛选出指定的一些用户(有特定年龄.职业.城市): 2.对这些用户在指定日期范围内发起的session,进行聚合统计,比如,统计出 ...