现有foo表,表结构如下
字段   A           B
       1        2010-4-22 11:30:16
      100       2010-3-22我想实现的功能是在对表foo进行insert和update时,如果A的值是‘1’的话,B的值自动更新为当前日期我写的触发器如下:
CREATE OR REPLACE TRIGGER AIUFER_FOO
  BEFORE INSERT OR UPDATE
   ON FOO
FOR EACH ROW 
DECLARE
  FOO_COUNT INT;
BEGIN
  SELECT COUNT(*) INTO FOO_COUNT FROM FOO 
   WHERE :NEW.A=1;
  IF FOO_COUNT>0  THEN
      :NEW.B:=SYSDATE;
  END IF;
END;编译没有错误我执行如下语句时
  INSERT INTO FOO VALUES(1,TO_DATE('20100305','YYYY-MM-DD'))
是正确的,b字段的值自动更新为当前日期但是当我执行
  UPDATE FOO SET A=1
就会出现如下错误:
ORA-04091:表abc.foo发生了变化,触发器和函数不能读等错误
请问这时什么原因,是触发器写的不正确吗?如果要实现上述的功能应该怎么写呢??
先谢谢各位了啊!!

解决方案 »

  1.   


    CREATE OR REPLACE TRIGGER AIUFER_FOO
      BEFORE INSERT OR UPDATE
      ON FOO
    FOR EACH ROW  
    BEGIN
      IF :NEW.A = 1 THEN
        SELECT SYSDATE INTO :NEW.B FROM DUAL;
      END IF;
    END;
    这样应该可以了,你试试。
      

  2.   

    变异表的问题,这种情况,需要用自治事务。
    CREATE OR REPLACE TRIGGER AIUFER_FOO
      BEFORE INSERT OR UPDATE
      ON FOO
    FOR EACH ROW  
    DECLARE
      PRAGMA AUTONOMOUS_TRANSACTION;
      FOO_COUNT INT;
    BEGIN
      SELECT COUNT(*) INTO FOO_COUNT FROM FOO  
      WHERE :NEW.A=1;
      IF FOO_COUNT>0 THEN
      :NEW.B:=SYSDATE;
      END IF;
    END;
      

  3.   

    那能不能解释一下,为什么在insert时候就不提示错误呢,而在update时确提示错误啊??
    谢谢各位了啊,我在加分!
      

  4.   

    还有个问题想问下五楼的兄弟啊,如果是after触发器的话,编译时就会有错误提示:ora-04084: 无法更改此触发器类型的new值,这时怎么回事啊?难道说如果是after触发器就不能使用 new 了吗??
      

  5.   

    SELECT COUNT(*) INTO FOO_COUNT FROM FOO  
      WHERE :NEW.A=1;
      IF FOO_COUNT>0 THEN
      :NEW.B:=SYSDATE;
      END IF;改为   if NEW.A=1 then 
           :NEW.B:=SYSDATE;
           END IF;
      

  6.   

    至于改为after后 因为此时值已经提交了  
    所以你不能在修改 :NEW.B 的值了
      

  7.   

    那能不能解释一下,为什么在insert时候就不提示错误呢,而在update时确提示错误啊??
    谢谢各位了啊,我在加分!
      

  8.   


    没找到这个资料,我瞎说一下:ORACLE有2种读,一种是一致性读(select语句在开始执行时,就确定了SCN, 如果数据块中的SCN比select时的大,就从回滚段中去取数据);一种是块读(BLOCK READ):update 时,where条件读取的是数据块中的的数据,用于处理并发。在after insert的触发器,只涉及一致性读,所以没有问题;在after update的触发器中,由于oracle已经更新了当前数据块中的值,select from FOO 需要一致性读(此时要从回滚段中读数据),此时读的数据已经不是最新的了(即是回滚段中的数据与当前块中的数据不一致),所以ORACLE就报错了那个异常出来,以避免发生脏读。