Database-Design
對外鍵使用 NULL 值並進行規範化
我正在創建一個表,如下所示:
Building (PK: buildingID) Area (PK: areaID, FK: buildingID) Room (PK: roomID, FK: buildingID, FK: areaID)
所有房間都在一棟樓內。部分客房可能位於建築物的某個區域內。不在建築物區域內的房間將 FK: areaID 設置為 NULL。
例如,建築物的區域包括:藍色區域、綠色區域、紅色區域。房間可以在這些區域之一,但可能不在一個區域內,而只是建築物本身的一部分。
這是否正確標準化?我覺得當 FK: areaID 設置為一個值時,它沒有被規範化,因為 buildingID 可以從 areaID 確定。
如果它沒有被規範化,我如何去規範化它以便 FK: areaID 仍然可以使用 NULL 值?
這是否正確標準化?
- 有可能輸入不匹配
(buildingID, areaID)
;Room
換句話說,在不屬於該房間所在建築物的建築物區域內擁有一個房間。- 說
Room.areaID
是NULL
。這是否意味著房間不在定義的區域之一,或者是否意味著該區域目前未知?鑑於規範化是關於從數據庫中刪除和防止邏輯錯誤(加上一些技術術語),答案是否定的。
正如 Eric S. 所建議的那樣,最簡單的方法是允許每個建築物都存在一個“未指定”區域。然後,對原始範例進行少量修改:
-- Building BLD exists. -- building {BLD} PK {BLD} -- Area ARE is located in building BLD. -- area {ARE, BLD} PK {ARE} FK {BLD} REFERENCES building {BLD} -- Room ROM is located in area ARE. -- room {ROM, ARE} PK {ROM} FK {ARE} REFERENCES area {ARE}
或者這個:
-- Building BLD exists. -- building {BLD} PK {BLD} -- Building area number ARE# of building BLD exists. -- area {BLD, ARE#} PK {BLD, ARE#} FK {BLD} REFERENCES building {BLD} -- Room number ROM# of building BLD -- is located in area number ARE# of that building. -- room {BLD, ROM#, ARE#} PK {BLD, ROM#} FK {BLD, ARE#} REFERENCES area {BLD, ARE#}
每棟樓的所在位置,是
ARE#
該樓的房間號。{0,1, ...}``ROM#
但是,如果我們不能為每個建築物提供一個通用(未指定)區域:
-- Building BLD exists. -- building {BLD} PK {BLD} -- Room number ROM# of building BLD exists. -- room {BLD, ROM#} PK {BLD, ROM#} FK {BLD} REFERENCES building {BLD} -- Building area number ARE# of building BLD exists. -- area {BLD, ARE#} PK {BLD, ARE#} FK {BLD} REFERENCES building {BLD} -- Room number ROM# of building BLD -- is located in area number ARE# of that building. -- room_area {BLD, ROM#, ARE#} PK {BLD, ROM#} FK1 {BLD, ROM#} REFERENCES room {BLD, ROM#} FK2 {BLD, ARE#} REFERENCES area {BLD, ARE#}
或者,使用(大部分)單列鍵:
-- Building BLD exists. -- building {BLD} PK {BLD} -- Room ROM is located in building BLD. -- room {ROM, BLD} PK {ROM} SK {ROM, BLD} FK {BLD} REFERENCES building {BLD} -- Area ARE is located in building BLD. -- area {ARE, BLD} PK {ARE} SK {ARE, BLD} FK {BLD} REFERENCES building {BLD} -- Room ROM located in building BLD, -- is located in area ARE, in that building. -- room_area {ROM, BLD, ARE} PK {ROM, BLD} FK1 {ROM, BLD} REFERENCES room {ROM, BLD} FK2 {ARE, BLD} REFERENCES area {ARE, BLD}
筆記:
All attributes (columns) NOT NULL PK = Primary Key AK = Alternate Key (Unique) SK = Proper Superkey (Unique) FK = Foreign Key
Using suffix # to save on screen space. OK for SQL Server and Oracle, for others use _NO. For example, rename ARE# to ARE_NO.
當存在可選關係並且此特定行不參與時,許多設計人員在外鍵中使用 NULL。
這沒什麼大不了的。當在這個 FK 和相應的 PK 上完成連接時,帶有 NULL 的行將被丟棄。其他設計師像瘟疫一樣避免這種情況。