我要对一张表,在写的SQL语句时更新第二个字段,触发器自动更新第三个字段(需求是时间),结果提示 
ora-04098:触发器“tri_key”无效且未通过重新确认。--对自身表触发修改
--创建表
drop table test_4;
create table test_4
(
  aa varchar2(10),
  bb varchar2(10),
  cc varchar2(10)
);--第一步:创建程序包,设立全局变量 
create or replace package proc_testtrigger
is
  p_aa   test_4.aa%type;
begin
  null;
end proc_testtrigger;
/--第二步:创建行触发器,将key值存入全局变量中
create or replace trigger tri_key
  after update on test_4 for each row
begin
  proc_testtrigger.p_aa := :new.aa;
end tri_key;
/ --第三步:创建表触发器,根本全局变量更新数据
create or replace trigger tri_upd
  after update on test_4
begin
  update test_4 set cc = 'zhi' where aa = proc_testtrigger.p_aa;
end tri_upd;
/ --插入数据
insert into test_4 (aa, bb, cc) values ('a', 'b', '');
insert into test_4 (aa, bb, cc) values ('a', 'c', '');
insert into test_4 (aa, bb, cc) values ('a', 'e', '');
--SQL语句,更新语句 ,想实现在更新的同时,触发器更新CC字段
update test_4 set bb = 'gggg' where aa = 'a';自身表触发修改,ORA-04098UPDATE

解决方案 »

  1.   

    没有这种用法。
    create or replace trigger tri_key
      before update on test_4 for each row
    begin
      :new.cc = 'zhi';
    end tri_key;
      

  2.   

    好麻烦,为什么不直接创建 before 触发器?
      

  3.   

    LZ竟然用包里的p_aa变量在两个触发器之间传递数值??
    变量作用域清楚吗?
      

  4.   

    额,不好意思,在同一SESSION下,包的全局变量是有效的.
    不过你的包定义有点问题:
    create or replace package proc_testtrigger
     is
       p_aa   test_4.aa%type;
     end proc_testtrigger;
    包头定义是不用BEGIN的
      

  5.   

    没效果,都考虑过
    --------------------------
    难道没有人做过对自身数据表进行DML操作的吗???
      

  6.   

    加上 包就是无效的了,
    Compilation errors for PACKAGE SCOTT.PROC_TESTTRIGGERError: PLS-00103: 出现符号 "BEGIN"在需要下列之一时:
            end function pragma
              procedure subtype type <an identifier>
              <a double-quoted delimited-identifier> current cursor delete
              exists prior
    Line: 4
    Text: beginError: PLS-00103: 出现符号 "end-of-file"在需要下列之一时:
            end not pragma
              final instantiable order overriding static member constructor
              map
    Line: 6
    Text: end proc_testtrigger;
    -----------
    我就是去掉了BEGIN使包有效之后就可以成功执行的
      

  7.   

    额,不好意思,确实不是这个的问题,是因为存在递归
    你触发器里使用UPDATE然后又触发了触发器,造成了死循环
    update test_4 set cc = 'zhi' where aa = proc_testtrigger.p_aa;
      

  8.   

    其实包和第一个触发器我不知道你干嘛用的  完全可以去掉:
    触发器这么写就可以了:create or replace trigger tri_upd
      before update on test_4
      for each row
    begin
      :new.cc := 'zhi';
    end tri_upd;
      

  9.   


    为什么会这么写?是因为,我在实际应用中,在更新某一行数据后,日期自动更新,按我的想法,只有先更新了(比如ID为3的)数据,触发器才知道应该把新的日期更新到ID为3的这条数据上。
    所以我一直想着触发器的解发点是更新完某一条数据后,才解发事件。但我不太明白为啥你写的触发器是用befor,而不是after.