1. 程式人生 > >不再迷惑,無值和NULL值

不再迷惑,無值和NULL值

空值 int 進行 命令 into 如果 returns 1-1 query

在關系型數據庫的世界中,無值和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值