選項#1確保每個頁面 屬於一個且僅一個其它 實體,儘管這種關係斜面 實際上被執行作爲parentId的 字段可以指向一個以上的 地方。
沒錯。就關係理論而言,問題在於您的「parentId
」列違反了third normal form,因爲它的含義根據parentType
(非關鍵列)中的值每行不同而不同。
如果單列可能包含某人的電話號碼或他們的出生日期,每行取決於其他標誌,那麼您將沒有設計合適的數據庫。這是關於這個人的兩個不同的事實,他們每個人都應該擁有自己的專欄。同樣,將site_id或node_id存儲在單個列中也會遇到同樣的問題。
這是一個有缺陷的設計的另一個線索是,您不能聲明一個外鍵約束指向或兩個引用表的。
選項#2是清潔的,但它的基本 說,該網站 「屬於」兩個錯誤,而不是 找到的頁面,這可能是壞 實踐。
我看到你爲什麼這麼說,因爲屬於Rails中類似的框架約定。但這些都是公約;它們不一定是外鍵可以建模的唯一關係。您可以讓一個實體參考另一個實體,在中有一個的關係。在這種情況下,外鍵反轉方向。
我想說這是錯誤頁面和未找到頁面屬於該網站在邏輯上是正確的,而不是相反。而使它們成爲強制的方法是讓另一個實體引用這些頁面,並將NOT NULL
約束應用於這些引用。這就是你所描述的。
CREATE TABLE site (
. . .
error_page_id INT NOT NULL,
notfound_page_id INT NOT NULL,
FOREIGN KEY (error_page_id) REFERENCES pages (page_id),
FOREIGN KEY (notfound_page_id) REFERENCES pages (page_id)
);
這滿足您的直接需求,它是可執行的,它是以正常形式。
@NXC suggests爲「錯誤」和「未找到」頁面創建虛擬節點。儘管這允許將這些節點存儲在節點層次結構中,但它不能強制網站必須具有這些頁面。也就是說,一個站點可以被存儲在而沒有對這些節點的引用。
@Tony Andrews suggests在每頁中存儲兩列,site_id
和site_node_id
,並添加一個CHECK約束以確保其中的一個非NULL。這似乎比parent_id
/parent_type
選項更好,但它仍不能提供任何強制措施,即每個站點都必須有「錯誤」和「未找到」頁面。
謝謝,這確實是最有意義的。由於頁面無法通過級聯刪除與該關係(因爲FK被反轉),您會建議使用觸發器來刪除鏈接的錯誤頁面,還是其他? – 2009-02-11 17:40:36