44

我有以下我的應用程序「意見」表:MySQL的 - 條件外鍵約束

comments 
-------- 
id   INT 
foreign_id INT 
model  TEXT 
comment_text TEXT 
... 

此表的想法是存儲我的應用程序的各個部分的意見 - 它可以存儲博客發表評論即:

1|34|blogpost|lorem ipsum... 

用戶圖片:

2|12|picture|lorem ipsum... 

等。

現在,有沒有辦法強制這些數據上的FOREIGN KEY約束?

即像這樣在comments表:

FOREIGN KEY (`foreign_id`) REFERENCES blogposts (`id`) 
//but only when model='blogpost' 

回答

71

你試圖做一個名爲多態關聯設計。也就是說,外鍵可以引用幾個相關表中的任何一箇中的行。

但是外鍵約束必須只引用一個表。您不能聲明引用不同表的外鍵,這取決於您的Comments表的另一列中的值。這會違反關係數據庫設計的幾個規則。

更好的解決方案是製作一種由評論引用的「超級」。

CREATE TABLE Commentable (
    id SERIAL PRIMARY KEY 
); 

CREATE TABLE Comments (
    comment_id SERIAL PRIMARY KEY, 
    foreign_id INT NOT NULL, 
    ... 
    FOREIGN KEY (foreign_id) REFERENCES Commentable(id) 
); 

您的每種內容類型都將被視爲此超可用的子類型。這類似於接口的面向對象的概念。

CREATE TABLE BlogPosts (
    blogpost_id INT PRIMARY KEY, -- notice this is not auto-generated 
    ... 
    FOREIGN KEY (blogpost_id) REFERENCES Commentable(id) 
); 

CREATE TABLE UserPictures (
    userpicture_id INT PRIMARY KEY, -- notice this is not auto-generated 
    ... 
    FOREIGN KEY (userpicture_id) REFERENCES Commentable(id) 
); 

,然後才能插入一行到BlogPostsUserPictures,必須插入一個新行Commentable生成一個新的pseudokey ID。然後,可以在將內容插入到相應的子類型表時使用該生成的ID。

一旦你做了所有這些,你可以依靠參照完整性約束。

+1

我假設UserPictures包含一個引用User表的字段user_id。你如何處理用戶刪除的方式,刪除將級聯到可評論的表格?我在這裏問過這個問題 - http://stackoverflow.com/questions/11497149/how-to-enforce-referential-integrity-on-single-table-inheritance - 如果你能解釋你如何處理這個問題,我會很感激打嗝我被卡住了。 – 2012-07-16 06:07:55

+13

@MattMcCormick,我不再回答這個問題了,因爲討厭的版主讓它無法參與。 – 2012-07-16 22:01:10

+2

哦,好的。感謝您過去的參與。我閱讀了很多有關單表繼承和多態關聯的答案,並且還觀看了您在其中一篇中引用的演講中的幻燈片。它幫助我更好地確定數據庫可能導致問題的情況。我已將您的書添加到我的閱讀列表中,並且可能會將其提供給我的下一本軟件書閱讀。 – 2012-07-16 22:30:16