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是否有一个外键
到tableORDERS
上执行触发器?这可能会导致类似的情况发生。您可以阅读更多@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
.
.
.