2015-08-19 52 views
3

我有一個表類別結構如下一行:MySQL的 - 防止引用本身

---------------------------------- 
| id (PK) | name | parentId (FK) | 
---------------------------------- 

其中的parentId可以在同一個表中引用的行。

我想阻止一個行被更新,以便它引用到它本身(parentId的!= ID)。我知道我必須使用數據庫觸發器,但我不知道它應該如何顯示。我該怎麼做?

我知道我可以(也將)在應用程序邏輯處理這個問題,但我不認爲這是一個很好的做法僅在應用程序邏輯處理這類事情。

我也想防止插入和更新循環引用,但我想這是一個不同的問題。

回答

0

很多谷歌搜索後,思維和閱讀教程,我已經成功地創建,我想我自己的觸發器:

DELIMITER $$ 
CREATE TRIGGER prevent_circular_reference 
    BEFORE UPDATE ON category 
    FOR EACH ROW BEGIN 
     DECLARE x INT; 
     SET x = NEW.parentId; 
     WHILE x > 0 DO 
      IF OLD.id = x THEN 
       SIGNAL SQLSTATE "45000" 
        SET MESSAGE_TEXT = "Cannot change parentId as it would create a circular reference."; 
      END IF; 
      SELECT parentId FROM category WHERE id = x INTO x; 
     END WHILE; 
    END;$$ 
DELIMITER ; 

扳機上表中的每個更新之前被解僱。它檢查應該成爲當前類別的父類別的類別不是當前類別的子類別。如果通過更新創建循環引用(包括引用自身的行),則使用SIGNAL關鍵字會引發錯誤。

注意,這是asssumes ID 設置爲自動增量從1開始(默認行爲),因爲如果SELECT返回NULL,零插入X

+0

你覺得這樣慢嗎?是否還使用了外鍵約束? http://dev.mysql.com/doc/refman/5.7/en/create-table-foreign-keys.html – dlamblin

+0

速度沒問題。此外,我將限制嵌套深度爲5或10(尚不確定),所以我懷疑會有任何顯着的速度懲罰。但我一直在谷歌搜索已經這和Oracle似乎快了很多:http://explainextended.com/2009/09/28/adjacency-list-vs-nested-sets-oracle/是的,使用FK約束。 –

3

這將是更容易檢查約束的事情:

ALTER TABLE categories 
ADD CONSTRAINT categories_no_self_ref_ck CHECK (id != parentid) 
+0

從MySQL文檔「的勾選子句分析,但是忽略所有的存儲引擎」 – Uueerdo

+0

5.7手動說:「CHECK值不可用,直到我們支持CHECK」。 http://dev.mysql.com/doc/refman/5.7/en/table-constraints-table.html – dlamblin

+0

正如其他人已經指出的,這不適用於MySQL。約束被簡單地忽略。這就是爲什麼我早些時候說我需要一個觸發器。 –