我可以無損地分解這張表嗎?
我偶然發現了一個超出我能力範圍的數據庫設計問題,而我的首選 DBA 大師正在參加消防演習。
本質上,我有一個帶有以下主鍵的表(為簡潔起見,PK):
child_id integer parent_id integer date datetime
child_id
並且parent_id
是實體表的外鍵。“子”表本身也包含“父”表的外鍵,而且,每個表child_id
總是引用與parent_id
上表預期相同的內容。事實上,事實證明有一些額外的程式碼使兩者保持同步。這使得這個過度熱情的標準化新手說“我應該刪除冗餘!”
我分解為以下內容:
Table_1 PK: child_id integer date datetime Table_2 PK: parent_id integer date datetime Table_3: (already exists) child_id integer PRIMARY KEY parent_id integer FOREIGN KEY
瞧,當我以自然的方式將這些傢伙聚集在一起時,我恢復了原來的桌子。這是我的理解,使這個 5NF。
然而,現在我意識到有一個隱藏的商業規則。
通常,與給定關聯的日期
child_id
必須是與對應的關聯的日期的子集parent_id
。您可以看到第一個表強制執行此規則。我的分解不強制執行規則,因為您可以自由地添加到表 1,直到日期變得太大。
這導致我來到這裡,有以下問題:
- 這是分解 5NF 嗎?雖然我會說它允許插入異常,但它似乎也遵循 Wiki 範例,該範例本身遵循本指南。片語(強調我的)“我們可以從由三種獨立記錄類型組成的規範化形式中重建所有真實事實”給了我特別的停頓,因為無論我泵入多少垃圾
Table_1
,自然連接仍然會忽略它。- 假設我不喜歡這種分解(我不喜歡)。我坦率地承認,實際的解決方案是讓表格和程式碼保持原樣。但是,理論上,有沒有辦法分解和/或添加約束,以便我擺脫第一個表並保留我的業務規則?
規範化是基於函式依賴的。功能依賴與語義有關;它們與數據的含義有關。當您將現實世界的問題簡化為“parent_id、child_id、date”級別並且不包含任何範例數據時,您確實限制了盡職盡責的數據庫設計人員可以為您提供多少幫助。
您在一個表中有一個鍵 {child_id, parent_id, date} 並且您(似乎)在子表中有一個唯一的對 {child_id, parent_id} 的事實並不一定意味著組合的一部分是多餘的. 這可能意味著在以 {child_id, parent_id, date} 作為主鍵的表中,屬性對 {child_id, parent_id} 應該首先引用子表。
如果是這種情況,您可以使用
FOREIGN KEY (child_id, parent_id) REFERENCES child (child_id, parent_id)
. 為此,您需要對錶“child”中的列對(child_id,parent_id)進行唯一約束,如果 child_id 是其主鍵,這應該不是問題。但是,如果不知道數據的含義,就無法判斷,而且你是這個執行緒中唯一知道這一點的人。(但我們很樂意讓您向我們解釋。)
就原始表而言,您似乎是在說 child_id -> parent_id。如果是這樣,為什麼 parent_id 首先在原始表中?為什麼鍵不只是(child_id,date),具有對“child”表的外鍵引用?在我看來,您所說的那種冗餘可以通過刪除“parent_id”列來解決。
SQL DDL 和 INSERT 語句形式的範例數據可以幫助我們幫助您。DDL 和 INSERT 語句比描述更精確。
嘗試這個…
(child_id,parent_id)
在子表中添加唯一約束- 您目前的表
(PK,FK:child_id, PK,FK:parent_id, PK:date)
保持原樣,FK 位於新唯一約束的 2 列上要麼
- 從目前子表中移除 FK
- 創建一個
(PK,FK:child_id, FK:parent_id)
與孩子 1:1的新表- 您目前的表
(PK,FK: child_id, PK,FK: parent_id, PK:date)
保持原樣。但 FK 在新表的 2 列上如果沒有別的,它可能會激勵你……
如果我理解正確,它將刪除冗餘和程式碼……