程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

觸摸Null

編輯:關於SqlServer


我們初步見識了NULL這個不可思議的小東西。今天,我盡可能詳細的介紹一下它。依照慣例,這是一次盡量淺顯但並不嚴謹的討論,甚至可能內容也不那麼嚴肅。我的目的在於幫助讀者更輕松地工作,並且有興趣對數據庫進一步的學習。從另一方面講,我相信自己論點中的錯誤,肯定會有其他人也在犯,所以請發現不妥的朋友一定要公開指出。這樣,才有助於我和我的讀者朋友們進步。衷心感謝每一個提出批評和指正的朋友,特別是公開提出批評和指正的朋友們。特別感謝sunshine19,專程發來E-mail,指出了《SQL Story》 的種種不足,並提出了寶貴意見。我期望他繼續關心這個專題,並期望他為我們帶來優秀的作品。

無可回避的不存在

例:雙人房間。

假設某個學校,它的單身職工公寓中,每個房間有兩個床位。這樣做有很多好處,比如安全,都是半大不小的年輕人,不管男孩女孩,有個伴一起住總讓人放心些,互相也有個照應;如果有誰結了婚,由於每個房間最多住兩個人,還可以比較容易地找出一間,先給他們安個家,慢慢等著分房。這些事當然不要我們程序員多操心(除非我們就住在裡面)。現在要關心的是,有人做了一個公寓管理數據庫。其中的房間管理表這樣子設計:

CREATE TABLE ROOMS(

ROOMID CHAR(5),

MASTERID CHAR(10) ,

SECONDID CHAR(10),

CONSTRAINT PK_ROOM PRIMARY KEY(ROOMID),

CONSTRAINT FK_MASTER FOREIGN KEY (MASTERID) REFERENCES LIVERS(ID),

CONSTRAINT FK_SECOND FOREIGN KEY (SECONDID) REFERENCES LIVERS(ID)

)

簡單介紹一下,管理員為了方便管理(比如收個水電費什麼的),要求每一個住人的房間有一個房主;兩個人更詳細的信息保存在了 LIVERS表中,所以我們看到有兩個外鍵約束。當然,這個設計並非無懈可擊,不過它也自有它的理由,在這裡我們先不討論了。

這裡要關注的是,房客少於兩個人的房間,我們該在空出來的地方填什麼?有一個方法,就是填入一個空字符串,可這樣一來,就等於我們默認了存在一個ID號為空字符串的住戶存在。因為空字符串也是字符串嘛。兩個外鍵約束也說明了這一點。事實上,在類似這樣的設計中,我就見過一些例子,其作者為了避免無可引用的情況,憑空造出一個不存在的信息,做為數據庫結構的一部分。具體到這個例子,可能會有人真的用一個空字符串或寫一個“NONE”什麼的,寫在LIVERS表中,表示沒有人居住。通常這會引起很多問題,比如我們可能要加一個約束,使得一個人不能出現在ROOMS表中兩次。可現在這個虛擬出來表示沒有人的房客怎麼辦?可有很多位置都沒有人啊,比如只要有一個空房,就會在這一條記錄上有兩個“NONE”!在更離奇(但在某些應用中絕非不可能)的情況下,有一個房客,他的ID就是“NONE”,如何??而且如果極端情況下,房客全搬出去了,怎麼辦?想要“DELET FROM LIVERS”都不行,“NONE” 可刪不掉啊。當你工作在這樣一個數據庫中,得時時提醒自己不要得罪了這個不存在的家伙。要記住,他沒有性別,所以男女職工的房間他都要住;別人一個人只能睡一張床,他卻可以要所有空閒的;別人都搬出去後,他老人家一個人占了所有的房間,我們的法律規章對他全沒有意義。這種特殊值給我們帶來的最大問題,就是把信息和數據庫結構攪在了一起。也就是說,關系和關系的模式混為一談了。如果一個數據庫中有上幾個這種表,誰都會瘋的。

這就是NULL的意義,當你把一個數據定義為NULL時,就等於告訴系統,這個數據不存在,或未知。不要管它了,它的內容沒有意義(當然,這本身也是一種意義)。在房間中有一個NULL,只表示沒有人,而不會被認為是一個叫“沒有人”的人住在裡面。更不會有一個霸占了所有房間的惡客存在。要清空LIVERS,那就清吧,只要你設置了級聯約束,就不會有任何離奇的事出現。唯一的後果只是一個無人居住的公寓而已,這不正是我們所要的嗎?

NULL是真實存在的,盡管從某種意義上講,我們無法解釋它的存在。它是關系世界的黑洞。也許會讓一些人不舒服,但回避它只會給我們帶來更多的麻煩。

看不見摸不到

在《SQL-3參考大全》中,作者這樣解釋NULL的含義:未知或未定義。對NULL來說,有很多有趣的特性。

NULL是一個數據值,而且它屬於一個域(?)。是的,例如一個字符串字段,其中的空值只能是一個字符串。盡管它的內容沒有定義,或者未知,但它是字符串,這一點無可置疑。

NULL不是非法數據,這一點SQL-3 標准也說的很清楚。我們沒有辦法保存零分之一,但可以保存空值。雖然它是空值,是未定義,是未知,可它也的確是 一個合法的信息。

運算黑洞:對於NULL,一般的運算都會返回NULL。比如加減乘除,這簡直就是一個黑洞一樣。永遠不會有什麼數據等於NULL。當然,1不等於NULL,2也一樣。可是,NULL也不等於NULL。說一個NULL等於NULL是錯誤的。所以我們只能比較它“是”或“不是”。為了避免混亂,SQL-3標准有一些約定。比如表達式 x=NULL,結果應當是UNKOWN 。 而表達式“x is NULL”,就得看情況,如果x是NULL或 False,就返回Ture(?);x是非NULL,返回False。有點奇怪是不是,它基於NULL不等於NULL。 這個規則的確為SQL標准所支持,遇到這樣的數據庫系統,可不要感到驚訝。

三值邏輯:《鹿鼎記》中的韋小寶,整人的秘訣之一就是“我問你話,是就點頭,不是就搖頭,不許你出聲!”的確,通常我們的邏輯觀點,總是基於這種二值邏輯體系,對就是對,錯就是錯。可在關系理論中,沒有這麼簡單。有一種沒有絕對是非的情況存在:NULL。這就是關系理論的三值邏輯。

還有一些常見的與NULL相關的情況。比如,統計函數(也有的文檔稱之為聚集函數、集函數)通常會忽略NULL。不過,假設有這樣一個表T:

C

-----

1

2

NULL

NULL

我們分別執行兩個查詢:SELECT COUNT(*) FROM T和SELECT COUNT(C) FROM T, 猜猜會有什麼不同?起初,我以為兩個結果應當一樣。結果,前一個是4,後一個是2。前一個等於4,顯然基於NULL也是數據這個事實;而後一個結果為2,是由於統計C列時,COUNT忽略了NULL。

SQL-3標准中,搜索條件(WHERE和HAVING)只接受TRUE,而約束卻只拒絕FALSE,二者對NULL的接受態度相反。所以我們前面見到的ROOMS表才可以把空值寫入人員字段。而在排序時,卻又沒什麼規律。SQL標准只作出了一個補充定義,所以每個DBMS的處理 ORDER BY的方法並不相同,當然NULL不是高於所有值就是低於所有值。

在《SQL-3參考大全》中介紹了更詳細的關於NULL的內容。另外,書中還介紹了兩位數據庫專家C.J.Date和E.f.Codd關於NULL的不同論點(E.F.Codd甚至希望有四值邏輯)有興趣的朋友可以找來一讀。在實踐中,我們還會遇到一些有趣的事,特別是聯接查詢中, NULL讓我們的人生變得 “豐富多彩”。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved