在被相同的 table 触发后,触发器无法读取 table

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

假设我有一个 table 如下--

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;

触发器在插入后触发并尝试从触发它的 table 中读取(逻辑上 duhh!)但是 oracle 给我一个错误并要求我修改触发器以便它不读取 table。错误代码-

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 ONO(这是 ORDER table 的主键)在 INSERTED 之后变成另一个 table。我不明白的是,为什么 oracle 会抱怨?触发器正在尝试读取 AFTER 插入!

想法?解决方案?

非常感谢

如果您尝试记录刚刚插入的 ONO,请使用 :new.ono 并完全跳过 select:

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

我不相信你可以 select 从你正在插入的 table 中,因为提交尚未发出,因此发生变异 table 错误.

P.S。考虑不缩写。让下一位开发人员清楚地知道并将其称为 ORDER_NUMBER 或至少是普遍接受的缩写,例如 ORDER_NBR,无论您公司的命名标准是什么。 :-)

仅供参考 - 如果您正在更新,您也可以访问 :OLD.column 更新前的值(当然如果该列不是主键列)。

放大@Gary_W的回答:

Oracle 不允许行触发器(其中包含 FOR EACH ROW 的行触发器)访问以任何方式定义触发器的 table - 您不能发出 SELECT、INSERT、UPDATE 或 DELETE 从触发器或它调用的任何东西中针对 table(所以,不,你不能通过调用一个为你做肮脏工作的存储过程来避开这个 - 但是好想法! :-)。我的理解是,这样做是为了防止您可能称之为 "trigger loop" 的情况 - 即满足触发条件并执行触发器的 PL/SQL 块;然后那个块做了一些导致触发器再次被触发的事情;触发器的 PL/SQL 块被调用;触发器的代码修改了另一行;等等,无穷无尽。通常,这应该被视为一个警告,表明您的逻辑要么非常丑陋,要么在错误的地方实现它。 (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 :-) 这允许您解决这些问题 - 但说真的,如果您遇到这样的问题,您最好的选择是重新处理数据,这样您就不必这样做了。

祝你好运。

修改触发器以使用 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
.
.
.