有沒有一般規則或最佳做法的外鍵不應該爲空。很多時候,一個實體不與另一個實體有關係是非常合理的。例如,您可能有一張您正在追蹤的藝術家的表格,但此刻,您沒有這些藝術家記錄的CD。對於可以是音樂/音頻或軟件的媒體(CD,DVD,BluRay),您可以擁有一個共同信息表,然後是兩個外鍵,每個擴展表一個(AudioData和SoftwareData ),但必須是NULL
。這提出了一種稱爲除了別的之外的獨佔弧的情況。 這個通常被認爲是有問題的。
想象一個超類和兩個派生類,如Java或C++的OO語言。表示,在一個關係模式的一種方法是:
create table Media(
ID int not null, -- identity, auto_generated, generated always as identity...
Type char(1) not null,
Format char(1) not null,
... <other common data>,
constraint PK_Media primary key(ID),
constraint FK_Media_Type foreign key(Type)
references MediaTypes(ID), -- A-A/V, S-Software, G-Game
constraint FK_Media_Format foreign key(Format)
references MediaFormats(ID) -- C-CD, D-DVD, B-BluRay, etc.
);
create unique index UQ_Media_ID_Type(ID, Type) on Media;
create table AVData(-- For music and video
ID int not null,
Type char(1) not null,
... <audio-only data>,
constraint PK_AVData primary key(ID),
constraint CK_AVData_Type check(Type = 'A',
constraint FK_AVData_Media foreign key(ID, Type)
references Media(ID, Type)
);
create table SWData(-- For software, data
ID int not null,
Type char(1) not null,
... <software-only data>,
constraint PK_SWData primary key(ID),
constraint CK_SWData_Type check(Type = 'S',
constraint FK_SWData_Media foreign key(ID, Type)
references Media(ID, Type)
);
create table GameData(-- For games
ID int not null,
Type char(1) not null,
... <game-only data>,
constraint PK_GameData primary key(ID),
constraint CK_GameData_Type check(Type = 'G',
constraint FK_GameData_Media foreign key(ID, Type)
references Media(ID, Type)
);
現在,如果你正在尋找一個電影,你搜索AVData表,然後與媒體表連接爲其餘的信息等軟件或遊戲。如果您有一個ID值,但不知道它是什麼類型,請搜索媒體表格,Type值會告訴您要連接三個(或更多)數據表中的哪一個。關鍵是FK是指到的泛型表,而不是它。
當然,電影或遊戲或軟件可以在多種媒體類型上發佈,因此您可以在Media
表和各個數據表之間具有交集表。 Otoh,那些通常貼有不同的SKU標籤,因此您可能還想將它們作爲不同的項目對待。
正如您所期望的那樣,代碼可能會變得相當複雜,但不是太糟糕。Otoh,我們的設計目標不是簡單的代碼,而是數據的完整性。這使得不可能將遊戲數據與電影項目混合。並且你擺脫了只有一個必須有一個值而其他必須爲空的一組字段。
MySQL不強制執行CHECK約束。 –
然後使用觸發器。 – TommCatt
非常感謝,由於截止日期的原因,我不得不放棄一個愚蠢的解決方案,但這對未來將有所幫助。 –