SQL Story摘錄(七)————觸控NULL值 (轉)

worldblog發表於2007-12-13
SQL Story摘錄(七)————觸控NULL值 (轉)[@more@]

前面的文章中,我們初步見識了NULL這個不可思議的小東西。今天,我儘可能詳細的介紹一下它。依照慣例,這是一次儘量淺顯但並不嚴謹的討論,甚至可能內容也不那麼嚴肅。我的目的在於幫助讀者更輕鬆地工作,並且有興趣對進一步的學習。從另一方面講,我相信自己論點中的錯誤,肯定會有其他人也在犯,所以請發現不妥的朋友一定要公開指出。這樣,才有助於我和我的讀者朋友們進步。衷心感謝每一個提出批評和指正的朋友,特別是公開提出批評和指正的朋友們。特別感謝sunshine19,專程發來E-,指出了《 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

我們分別兩個查詢: 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標準只作出了一個補充定義,所以每個MS的處理 ORDER BY的方法並不相同,當然NULL不是高於所有值就是低於所有值。

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

由於種種原因,近幾天我可能會放慢寫作速度,但這並不代表我會放棄。在休整和充電之後,我會回到我所擅長的實戰領域。再次感謝每一位關心《SQL Story》的讀者。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-992884/,如需轉載,請註明出處,否則將追究法律責任。

相關文章