Trigger cant read the table, after being fired by the same table

时间秒杀一切 提交于 2019-12-07 21:51:46

问题


Lets say I have a table as follows--

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

I've created a trigger using the following code block

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;

The trigger fires after insertion and attempts to read from the table that fired it(logically duhh!) but oracle is giving me an error and asking me to modify the trigger so that it doesnt read the table. Error code-

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.

What I'm trying to achieve with this trigger is to copy the last INSERTED ONO (which is a primary key for the ORDER table) immediately to a different table after being INSERTED. What I don't get is, why oracle complaining? The trigger is attempting to read AFTER the insertion!

Ideas? Solution?

MANY THANKS


回答1:


If you are trying to log the ONO you just inserted, use :new.ono and skip the select altogether:

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

I don't believe you can select from the table you are in the middle of inserting into as the commit has not been issued yet, hence the mutating table error.

P.S. Consider not abbreviating. Make it clear for the next developer and call it ORDER_NUMBER or at least a generally accepted abbreviation like ORDER_NBR, whatever your company's naming standards are. :-)

FYI - If you are updating, you can access :OLD.column as well, the value before the update (of course if the column is not a primary key column).




回答2:


Amplifying @Gary_W's answer:

Oracle does not allow a row trigger (one with FOR EACH ROW in it) to access the table on which the trigger is defined in any way - you can't issue a SELECT, INSERT, UPDATE, or DELETE against that table from within the trigger or anything it calls (so, no, you can't dodge around this by calling a stored procedure which does the dirty work for you - but good thinking! :-). My understanding is that this is done to prevent what you might call a "trigger loop" - that is, the triggering condition is satisfied and the trigger's PL/SQL block is executed; that block then does something which causes the trigger to be fired again; the trigger's PL/SQL block is invoked; the trigger's code modifies another row; etc, ad infinitum. Generally, this should be taken as a warning that your logic is either really ugly, or you're implementing it in the wrong place. (See here for info on the evil of business logic in triggers). If you find that you really seriously need to do this (I've worked with Oracle and other databases for years - I've really had to do it once - and may Cthulhu have mercy upon my soul :-) you can use a compound trigger which allows you to work around these issues - but seriously, if you're in a hole like this your best option is to re-work the data so you don't have to do this.

Best of luck.




回答3:


Modify your trigger to use 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
.
.
.


来源:https://stackoverflow.com/questions/34362598/trigger-cant-read-the-table-after-being-fired-by-the-same-table

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!