2016-07-25 68 views
2

我知道這是一個奇怪的問題,因爲我總是被教導使用外鍵約束。但是,我遇到過一種情況,即在刪除引用時必須保留外鍵引用值用於歷史目的。外鍵總是需要約束嗎?

這是一個任務管理系統,任務發生引用包含重複規則的父任務。這個父任務可以被刪除,但事件本身必須保持與不存在的父母標識一致。如果找不到父任務,則系統僅返回一個錯誤 - 例如「父任務不再存在」。父級id不能在級聯中設置爲null的原因是因爲它在事件的其他地方用作識別密鑰。

另一個示例:關於從播放列表中刪除的YouTube視頻怎麼樣。類似的情況對嗎?它在播放列表中被引用,但視頻不存在,因此它會在播放列表中返回錯誤。

難道我根本就沒有定義外鍵,只是簡單地將parent_id引用列創建爲普通列?我只想確定當遇到一個表引用另一個表的情況時通常如何處理,但前者不受後者存在的約束。

+0

從技術上講,ON DELETE SET NULL原因將爲您處理。如果你的問題是理論上的話,那麼:是的,你可以:) – Koshinae

回答

4

有一個約束只是一個強制爲數據庫定義的語義的技術幫助,即「該列包含的數字不僅是一個INTEGER(32),而且是某個其他表中的記錄的標識符」。所以,他們不是絕對必要的,但它:

  • 使得野清晰(自文檔)的意圖
  • 使您的數據「乾淨」通過防止被插入
  • 給出了不正確的數據數據庫引擎提供有關表的內容的提示,可以使db更高效地執行。

也就是說,完成你所描述的「正確」方式並不是在物理上首先刪除父記錄。相反,將父項標記爲已刪除。既然你爲了歷史目的而保留記錄,當然你會希望能夠知道父母曾經是什麼,即使它不再活躍或有效。

第二種選擇是創建一個虛擬的「父記錄刪除」引用。無論何時刪除父項,都會更新剩餘的引用來指向虛擬記錄。至少你不會依賴錯誤來實現預期的和有效的行爲。

最後,我沒有理由不應該能夠將外鍵設置爲NULL。這聽起來像你正在使用外鍵作爲有問題記錄主鍵的一部分(「正被用作..識別鍵」)。如果這是問題的根本原因,那麼你幾乎肯定不應該這樣做,首先要改變它。

+0

我想過軟刪除,但父任務可以由另一個用戶創建。其他用戶可以訂閱這個父任務,因此會出現任務。但是,如果創建原始任務的原始用戶希望刪除該任務,則預期的結果是將其從數據庫中刪除,並將事件保存爲已訂閱的其他用戶的記錄。我的意思是,當記錄的所有者明確要求記錄時,不刪除記錄是否可以(甚至合法)? – chaser

+0

我無法將外鍵設置爲NULL,因爲它將原始任務分組爲5個子任務的分區變得複雜。這些分組需要在所有情況下保持完好 - 所以這就是爲什麼需要識別密鑰。 – chaser

+0

由於分組問題,不確定第二個選項 - 它基本上與NULL選項類似。但我想,如果我把所有其他設置爲NULL,除了ID ...它可以工作嗎?至少它就像是一個軟刪除,沒有實際的內容 - 那麼它會滿足業主對刪除的期望......一張滿了NULL的表聽起來不對,但我不得不多想這些。 .. – chaser

0

難道我根本就沒有定義一個外鍵,只是簡單地創建一個普通列的 parent_id引用列?

是的。至少這是我知道的方式,以及我們在工作中如何處理這些東西。

然後,您可能需要在參考列上設置索引。