ORA-04091 表 ODB.EMPLOYEE 正在变异,触发器/函数可能看不到它。我的触发器有问题吗?

Posted

技术标签:

【中文标题】ORA-04091 表 ODB.EMPLOYEE 正在变异,触发器/函数可能看不到它。我的触发器有问题吗?【英文标题】:ORA-04091 TABLE ODB.EMPLOYEE IS MUTATING, TRIGGER/FUNCTION MAY NOT SEE IT. IS THERE SOMETHING WRONG WITH MY TRIGGER? 【发布时间】:2021-05-10 19:31:01 【问题描述】:

尝试在员工表上的状态更新时创建触发器,并为该记录的 Employee 表和 Employee_Header 表中的记录捕获一些值并发送电子邮件。触发器抛出错误。

CREATE OR REPLACE TRIGGER ODB.TRG_EMPLOYEE_STATUS_EMAIL 
AFTER UPDATE OF STATUS ON ODB.EMPLOYEE 
FOR EACH ROW
DECLARE

  s_message varchar2(4000);
  s_subject varchar2(1000);
  s_return_message varchar2(4000);
  s_database varchar2(50);
  v_rm   EMPLOYEE%ROWTYPE;
  v_sh EMPLOYEE_HEADER%ROWTYPE;

BEGIN
  if :old."STATUS"  = 'HOLD' AND :new."STATUS"  = 'ACTIVE' AND :new."CATEGORY" = 'FULLTIME' then
   
    
select * into v_rm from EMPLOYEE WHERE :new."STATUS"  = 'ACTIVE' AND ROWNUM>1;
select * into v_sh from EMPLOYEE_HEADER WHERE ROWNUM>1;

    s_subject := 'NAME ' || v_rm.NAME ||' message ' || ' CHECK LOG OF EMPLOYEE' || Chr(13) || '   STATUS:  ' || v_rm.STATUS ;
    s_message := 'SAMPLE' || Chr(10)||Chr(13) || 'THE STATUS IN EMPLOYEE_HEADER IS: ' || Chr(10)|| '     STATUS:  ' || v_sh.STATUS ;

    pkg_email.sendEmail('INPUT PARAMETERS TO SEND EMAIL');
  end if;
END;

【问题讨论】:

【参考方案1】:

您无法从刚刚更改的表格中进行选择;它正在变异。不过,由于您可以使用 :new 伪记录,您可以“跳过”该错误。此外,where rownum > 1 是无用的,因为它从来都不是真的。我不知道你用它是什么意思。

我看到您使用双引号创建了列。在 Oracle 中,这通常是一个错误。并不是说它不起作用 - 它会起作用,但您总是必须使用双引号引用列并匹配字母大小写。

最后,触发器可能如下所示(在代码中读取 cmets):

create or replace trigger odb.trg_employee_status_email 
  after update of status on odb.employee 
  for each row
declare
  s_message varchar2(4000);
  s_subject varchar2(1000);
  s_return_message varchar2(4000);
  s_database varchar2(50);
  -- v_rm   employee%rowtype;  -- you don't need that
  v_sh employee_header%rowtype;
begin
  if :old."status"  = 'HOLD' and :new."status"  = 'ACTIVE' and 
     :new."category" = 'FULLTIME' 
  then
    -- You can't select from a table which is just being changed - it is "mutating".
    -- Besides, AND ROWNUM > 1 will never return anything. You can only check
    -- ROWNUM <= some_value
    --select * into v_rm from employee where :new."status"  = 'ACTIVE' and rownum>1;
    
    select * into v_sh from employee_header where rownum>1;

    -- instead of SELECT ... INTO V_RM, use :NEW pseudorecord
    s_subject := 'NAME ' || :new.name ||' message ' || ' CHECK LOG OF EMPLOYEE' 
      || chr(13) || '   STATUS:  ' || :new.status ;
    s_message := 'SAMPLE' || chr(10)||chr(13) || 'THE STATUS IN EMPLOYEE_HEADER IS: ' || chr(10)|| '     STATUS:  ' || v_sh.status ;

    pkg_email.sendemail('INPUT PARAMETERS TO SEND EMAIL');
  end if;

exception 
  when no_data_found then null;
end;

【讨论】:

现在按要求工作。最后一个问题是如果 v_sh 没有记录我该怎么办,它会抛出一个错误,说没有找到数据。当 v_sh 中没有记录时,我如何终止触发器或不发送电子邮件?非常感谢您的时间和投入。 如果查询没有返回任何内容,它将返回 NO_DATA_FOUND。你可以处理它来做某事,或者什么都不做——我编辑了触发代码并添加了后者的异常部分——什么都不做。您可以根据需要进行调整。 嗯,@sree 不应该有 惊喜 where rownum &gt; 1 的查询不会返回任何结果。你的意思是where rownum = 1 得到一个任意的行吗?

以上是关于ORA-04091 表 ODB.EMPLOYEE 正在变异,触发器/函数可能看不到它。我的触发器有问题吗?的主要内容,如果未能解决你的问题,请参考以下文章

ORA-04091: 表名正在变异

ORA-04091: 表 [blah] 正在变异,触发器/函数可能看不到它

ORA-04091: 表 JOSEP.EMP 正在变异,触发器/函数可能看不到它

如何修复 ORA-04091:表正在变异,触发器/函数可能看不到它?

oracle 触发器 ORA-04091

ORA-04091:表正在变异,触发器/函数可能看不到它,ORA-06512:,ORA-06512:在“SYS.DBMS_SQL”,第 1721 行