Database-Design

對外鍵使用 NULL 值並進行規範化

  • October 18, 2021

我正在創建一個表,如下所示:

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 值?

這是否正確標準化?

  1. 有可能輸入不匹配(buildingID, areaID)Room換句話說,在不屬於該房間所在建築物的建築物區域內擁有一個房間。
  2. Room.areaIDNULL。這是否意味著房間不在定義的區域之一,或者是否意味著該區域目前未知?

鑑於規範化是關於從數據庫中刪除和防止邏輯錯誤(加上一些技術術語),答案是否定的。


正如 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 的行將被丟棄。其他設計師像瘟疫一樣避免這種情況。

引用自:https://dba.stackexchange.com/questions/216083