2015-12-18 19 views
1

可以說我有作爲follows--觸發不能讀取表,由同一臺被解僱後

create table employees 
(
eno  number(4) not null primary key, 
ename varchar2(30), 
zip  number(5) references zipcodes, 
hdate date 
); 

我用下面的代碼塊

create or replace TRIGGER COPY_LAST_ONO 
AFTER INSERT ON ORDERS 
FOR EACH ROW 
DECLARE 

ID_FROM_ORDER_TABLE VARCHAR2(10); 

BEGIN 

SELECT MAX(ORDERS.ONO)INTO ID_FROM_ORDER_TABLE from ORDERS ; 
DBMS_OUTPUT.PUT_LINE(ID_FROM_ORDER_TABLE); 

INSERT INTO BACKUP_ONO VALUES(VALUE1, VALUE2,VALUE3, ID_FROM_ORDER_TABLE); 

END; 
創建觸發器的表

觸發器在插入後觸發,並嘗試從表中讀取(邏輯上duhh!),但是oracle給了我一個錯誤並要求我修改觸發器,以便它不讀取表。錯誤代碼 -

Error report - 
SQL Error: ORA-04091: table TEST1.ORDERS is mutating, trigger/function may not see it 
ORA-06512: at "TEST1.COPY_LAST_ONO", line 8 
ORA-04088: error during execution of trigger 'TEST1.LOG_INSERT' 
04091. 00000 - "table %s.%s is mutating, trigger/function may not see it" 
*Cause: A trigger (or a user defined plsql function that is referenced in 
     this statement) attempted to look at (or modify) a table that was 
     in the middle of being modified by the statement which fired it. 
*Action: Rewrite the trigger (or function) so it does not read that table. 

我試圖實現與該觸發器是被INSERTED後複製的最後INSERTEDONO(這對於ORDER表的主鍵)立即向不同的表。我不明白的是,爲什麼oracle抱怨?觸發器試圖讀取AFTER的插入!

想法?解?

千恩萬謝

+0

是否'BACKUP_ONO'表有一個'外國key'到餐桌'ORDERS'在其上觸發執行?這可能會導致這樣的事情發生。你可以閱讀更多http://www.dba-oracle.com/t_avoiding_mutating_table_error.htm – InSane

+0

@InSane沒有那樣的情況。 'BACKUP_ONO'只有一個主鍵。但是有一個屬性名爲'ONO',因爲我將它從'ORDERS'複製到'BACKUP_ONO' – envyM6

+1

也許與您的錯誤無關 - 但是使用ONO不是更好:NEW而不是嘗試通過MAX獲取?您的訂單中可能已插入ONO? – InSane

回答

3

如果你嘗試登錄的ONO您剛剛插入,使用:new.ono和完全跳過選擇:

INSERT INTO BACKUP_ONO VALUES(VALUE1, VALUE2,VALUE3, :new.ono); 

我不相信你可以從你的表中選擇在插入的過程中,由於提交尚未發佈,因此存在突變表錯誤。

P.S.考慮不要縮寫。爲下一個開發人員明確說明,並將其稱爲ORDER_NUMBER或至少一個普遍接受的縮寫,如ORDER_NBR,無論您的公司的命名標準如何。 :-)

僅供參考 - 如果您正在更新,您可以訪問:OLD.column以及更新前的值(當然如果該列不是主鍵列)。

+0

我們有一個贏家!所以讓我弄清楚這一點。 ':NEW.ONO'或'NEW.PRIMARY_KEY'返回插入的最後一個主鍵? – envyM6

+0

不是ONO的主鍵? –

+0

這是,我試圖讓語法正確..我的理解是正確的嗎? – envyM6

1

放大@ Gary_W的回答是:

Oracle不允許一個行觸發器(一個與它FOR EACH ROW)來訪問該觸發器以任何方式定義的表 - 你不能發出SELECT,INSERT ,UPDATE或DELETE在觸發器內部或者它所調用的任何東西上進行刪除(所以,不,你不能通過調用一個存儲過程來避免這種骯髒的工作 - 但是很好的思考!:-)。我的理解是,這樣做是爲了防止你可能稱之爲「觸發循環」 - 也就是說,滿足觸發條件並執行觸發器的PL/SQL塊;該塊然後做了一些事情,導致觸發器再次被觸發;觸發器的PL/SQL塊被調用;觸發器的代碼修改另一行;無限廣告等。一般來說,這應該被看作是你的邏輯要麼非常難看,要麼就是在錯誤的地方實現它的警告。 (See here for info on the evil of business logic in triggers)。如果你發現你真的認真必要做這個(我已經與Oracle等數據庫工作多年 - 我真的做一次 - 而且可能邪神憐恤我的靈魂: - )you can use a compound trigger它允許你解決這些問題 - 但是,嚴重的是,如果你在這樣的洞中,最好的選擇是重新處理數據,所以你不必這樣做。

祝你好運。

+0

BOB我真的很驚訝你的答案!我真的是!我不得不從爸爸谷歌尋求幫助,以瞭解你在做什麼!大聲笑..但嘿上面的觸發器工作。 :) – envyM6

0

修改您的觸發器使用PRAGMA AUTONOMOUS_TRANSACTION

create or replace TRIGGER COPY_LAST_ONO 
AFTER INSERT ON ORDERS 
FOR EACH ROW 
DECLARE 

    ID_FROM_ORDER_TABLE VARCHAR2(10); 
    PRAGMA AUTONOMOUS_TRANSACTION; -- Modification 
BEGIN 
. 
. 
.