2012-01-02 23 views
1

之前,我將嘗試使用觸發器來避免在某些情況下在表Products刪除一排。代碼如下突變表中的觸發器

CREATE TRIGGER trgPreventProductRemoval 
    BEFORE DELETE ON Products 
    FOR EACH ROW 

    BEGIN 
     DECLARE 
      l_custid INTEGER; 
     BEGIN 
      SELECT count(*) INTO l_custid FROM Orders WHERE product = :old.prodDescription ; 

      IF l_custid > 0 THEN 
       raise_application_error (-20100, 'You can not delete a product that has active orders!'); 
      END IF; 
     END; 
    END; 

但是我得到的錯誤:table ORDERS is mutating, trigger/function may not see it

我該如何解決?

編輯-SOLUTION:我已經接受了下面,因爲它是「政治正確」的解決方案。由於某些「限制」,我無法使用它並最終找到了不同的解決方法。看到我單獨發佈的解決方案。

+0

的可能重複的[ORA-04091:表\ [嗒嗒\]被突變,觸發/功能可能無法看到它](http://stackoverflow.com/questions/375968/ora-04091-table-blah-is -mutating-trigger-function-may-not-see-it) – Sathya 2012-01-03 04:15:10

回答

5

在訂單和產品表之間使用外鍵代替觸發器。

+0

這將是更清潔的解決方案,但我不能這樣做。 – niels 2012-01-02 18:34:21

+4

不允許?這似乎有點荒謬。外鍵的全部目的是爲了解決你所面臨的問題。我知道你是這裏的「受害者」,是一個非常非常糟糕的政策。但是,考慮到你一定會遇到的競爭條件和鎖定問題,你可能會反對使用外鍵的政治鬥爭,而不是試圖對其進行編碼。 – 2012-01-02 18:51:01

+0

@Mark J. Bobak:我在做H/W,我必須用觸發器來做,因爲我被要求這樣做。如果我必須選擇,我肯定會用fkeys來做。 – niels 2012-01-02 18:57:55

0

不能修復這個錯誤,因爲你從選擇的表在DML操作過程中的會話你因此無法確定在查詢時對查詢的回答是什麼。

有,然而,一個稍顯凌亂,但簡單的方法解決這問題:

  1. 創建形式select * from products的景色。
  2. 在視圖上編譯觸發器而不是表格。
  3. 確保觸發器執行你居然打算表的DML操作(凌亂的部分)。
  4. 只對視圖而非表格執行DML操作。

所以,這樣的事情應該工作。

create or replace view v_products as select * from products; 

CREATE TRIGGER trgPreventProductRemoval 
    BEFORE DELETE ON v_products 
    FOR EACH ROW 

    DECLARE 

    l_custid INTEGER; 

    BEGIN 

     SELECT count(*) INTO l_custid 
     FROM Orders 
     WHERE product = :old.prodDescription; 

     IF l_custid > 0 THEN 
     raise_application_error (-20100, 'You can not delete a product that has active orders!'); 
     END IF; 

     -- assumed, I don-t know the actual columns. 
     delete from products where product = :new.product_id; 

    END trgPreventProductRemoval; 
+0

@niels那會是因爲我忘了添加一個'declare' - 我已經編輯了答案;我從語法中推斷出Oracle,這都是Oracle,所以不用擔心。但是,在這個特例中,@ shannon的解決方案實際上比我的這個小小的破解要好得多。 – Ben 2012-01-02 19:32:26

+0

這不起作用,因爲Oracle不允許在視圖上使用「之前」觸發器。這並不重要,因爲我找到了一種適用於我正在使用的特定數據庫的解決方法(請參閱我的發佈解決方案)。謝謝你的關心。 – niels 2012-01-02 19:43:44

0

問題是最後,除去ProductsOrders之間的「鏈接」來解決。該鏈接是一個名爲SuplProd的中間表的外鍵中的ON DELETE CASCADE。通過從SuplProd的fk中去除ON DELETE CASCADE,表Orders變爲非變異。

要利用用於去除ON DELETE CASCADE,我剛添加的觸發器的代碼一行代碼,只是END IF;

後因此,從技術上說,這種解決方法的工作原理進行必要的表中的非變異的。