如何用 UNIQUE 索引和外鍵表示它?
“小組”是一群學生。“主題”是課程的主題。
每個組都對應一個主題。(因此每個主題可能有多個組。)
一個學生對應多個組,但每個主題最多一個組。
如何根據 MySQL 中的 UNIQUE 索引和外鍵來實現這一點?
這是一個常見的問題。“訣竅”是:
- 添加
Groups
- 除了主鍵 - 上的冗餘唯一約束(Topic, Group)
。- 這允許您
Topic
在關係中添加屬性Participates
和- 強制您將 Foreign Key 約束從 to 修改
Participates
,Groups
因此它Topic
不僅包括Group
.- 然後您可以添加唯一約束
Participates (Pupil, Topic)
(意味著學生只能參與一次主題,而不是兩次或更多,這是想要的結果。)Topics Topic PK Lessons Lesson PK Topic FK -> Topics Groups Group PK UQ1 Topic UQ1 FK -> Topics Pupils Pupil PK PupilParticipatesInGroup Pupil PK UQ1 FK1 -> Pupils Group PK FK2 -> Groups Topic UQ1 FK2
附錄
Abbreviation Constraint ------------ ----------- PK Primary Key UQ Unique FK Foreign Key
請注意,設計已經完成,**
3NF
**並且冗餘唯一約束Topics
僅在大多數 DBMS 中實現時才需要(因此強制執行外鍵。)唯一的另一個問題是
Group -> Topic
關係中的依賴Participates
關係使模式違反**BCNF
**。在連結頁面的Achievability of BCNF段落中,您會看到已證明並非所有表都可以分解為滿足
BCNF
並保留原始表中包含的依賴關係的表。Participates
提供的範例與此處的表格非常相似:在某些情況下,非 BCNF 表無法分解為滿足 BCNF 並保留原始表中保存的依賴關係的表。Beeri 和 Bernstein 在 1979 年表明,例如,一組函式依賴
{AB → C, C → B}
不能用 BCNF 模式表示。$$ 6 $$因此,與前三種範式不同,BCNF 並不總是可以實現的。
儘管如此,讓我們再做一個改變,以解決這個問題(如果可以的話!):
讓我們檢查一下如果我們從
Primary Key (Group)
約束中刪除(好像它從未存在過)Groups
(並將唯一性放在它的位置)會發生什麼。讓我們也將主鍵更改為Participates
- 注意 - 從一開始就是我們的目標的唯一約束. 設計變為(前兩個表被省略,因為它們保持不變):Groups Group PK Topic PK FK -> Topics Pupils Pupil PK PupilParticipatesInGroup Pupil PK FK1 -> Pupils Group FK2 -> Groups Topic PK FK2
根本沒有多餘的列。魔法!這是和(正如我們的模型想要的那樣)
Participates
之間的常見多對多關係,並且兩個外鍵引用相應表的主鍵。Groups``Pupils
所以發生了什麼事?魔法?(不是真的,不是)而且不是
Group
仍然是候選鍵Groups
嗎?(無論如何,刪除它只是一個思想實驗。)從實際表中省略這個約束,我們不會失去一些東西嗎?問題 - 以及上述解決問題的原因 - 是您嘗試建模的唯一約束需要關係中的
Topic
屬性Participates
。因此,您必須使用Groups
複合且包含的候選鍵Topic
。它不一定是(Topic, Group)
. 它可能是其他一些組合。還有什麼其他屬性Groups
?例如,如果and中有一個屬性
OrderNo
是唯一的,那麼我們可以有這樣的設計(終於!),沒有冗餘,沒有多餘的屬性,所有約束都在那裡,並且模式位於:Groups``(Topic, OrderNo``BCNF
Groups Group PK Topic UQ1 FK -> Topics OrderNo UQ1 Pupils Pupil PK PupilParticipatesInGroup Pupil PK FK1 -> Pupils Topic PK FK2 -> Groups OrderNo FK2