Oracle 触发器被同一个表触发后无法读取该表

Oracle 触发器被同一个表触发后无法读取该表,oracle,plsql,oracle11g,oracle-sqldeveloper,Oracle,Plsql,Oracle11g,Oracle Sqldeveloper,假设我有一张如下的桌子-- 我使用以下代码块创建了一个触发器 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_OR

假设我有一张如下的桌子--

我使用以下代码块创建了一个触发器

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.
我试图通过此触发器实现的是在插入
后立即将最后插入的
ONO
(它是
顺序
表的主键)复制到另一个表中。我不明白的是,为什么oracle会抱怨?触发器尝试在插入后读取

想法?解决方案


非常感谢

如果您试图记录刚刚插入的ONO,请使用
:new.ONO
并跳过选择:

INSERT INTO BACKUP_ONO VALUES( VALUE1, VALUE2,VALUE3, :new.ono);
<> P>我不相信你可以从你插入的表格中选择,因为提交还没有发布,因此发生了突变表错误。

考虑不要缩写。让下一位开发者明白这一点,并称之为ORDER_NUMBER或至少是一个普遍接受的缩写,如ORDER_NBR,无论您公司的命名标准是什么::-)


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

放大@Gary_W的答案:

Oracle不允许行触发器(其中每行都有
)以任何方式访问定义了触发器的表-您不能从触发器或其调用的任何内容中对该表发出SELECT、INSERT、UPDATE或DELETE命令(所以,不,你不能通过调用一个为你做脏活的存储过程来回避这个问题-但是想法不错!-)。我的理解是,这样做是为了防止你所谓的“触发器循环”-也就是说,满足触发条件并执行触发器的PL/SQL块;然后该块执行导致再次触发触发器的操作;调用触发器的PL/SQL块;触发器的代码无限修改另一行;等等。通常,这应该被视为警告,即您的逻辑不是真的ugl就是真的ugly、 或者你在错误的地方实现了它……如果你发现你真的真的需要这么做(我已经与Oracle和其他数据库合作多年了——我真的不得不这么做过一次——也许Cthulhu会怜悯我的灵魂:-)这让你能够解决这些问题——但说真的,如果你陷入这样的困境,你最好的选择就是重新处理数据,这样你就不必这么做了


祝您好运。

修改您的触发器以使用布拉格自治\u事务

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
.
.
.

BACKUP\u ONO
table是否有一个
外键
到table
ORDERS
上执行触发器?这可能会导致类似的情况发生。您可以阅读更多@InSane no并非如此。“BACKUP\u ONO”只有一个主键。但在我从中复制时,有一个属性的名称与
ONO
相同<代码>命令
备份(ONO)
可能与您的错误无关-但使用:NEW获取ONO不是更好,而不是尝试通过MAX获取它吗?您可能在插入的命令中有ONO?嗯…如果备份(ONO)中没有FK,那么您也会让我难堪:-@inase
:NEW.ONO
工作得很有魅力!!谢谢大家!我们有一个赢家!!所以让我直说吧
:NEW.ONO
NEW.PRIMARY\u KEY
返回插入的最后一个主键?ONO不是主键吗?是的,我正在尝试正确的语法。。我的理解正确吗?:NEW.ONO是您想要的。使用BEFORE DELETE触发器并记录:OLD.column\u name values ob我对您的答案感到非常惊讶!我真的是!我不得不向谷歌老爹寻求帮助,以了解你在说什么!英雄联盟但是,嘿,上面的触发器起作用了。:)@如果上面的触发器起作用,那只是因为您从中删除了select语句。@EriksonRodriguez:我怀疑来自envyM6的原始注释是指VidyaPandey答案中的触发器,该答案使用了
PRAGMA autonomy_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
.
.
.