ITPub博客

首页 > 数据库 > Oracle > 关于oracle触发器中修改自身表字段的问题

关于oracle触发器中修改自身表字段的问题

Oracle 作者:Itdoosmean 时间:2011-07-23 11:35:47 0 删除 编辑

之前写了一个oracle触发器,两个系统之间通过接口传递数据的时候,当一个表被写入数据时,引发一系列数据表的动作

create or replace trigger biufer_w_pz_jspbm
after insert on w_pz
for each row
declare
PRAGMA   AUTONOMOUS_TRANSACTION;
v_loc    varchar2(100);   

ret      VARCHAR2(1000);
v_lryno  varchar2(16);
v_no     varchar2(18);
v_num  NUMBER(4,0);
begin
    if  judgedate(SYSDATE)= 0 then
    begin

    v_loc := '1.insert W_PZ_WEB';
    INSERT INTO W_PZ_WEB  
    (NO,FM,NRJJ,ZZJJ,MBDZ,YS,VALIDDATE,LRYNO,MEMO,DJL,ZDFLAG)
    SELECT  :new.NO,W_PZ_NEWDATA.FM,W_PZ_NEWDATA.NRJJ,W_PZ_NEWDATA.ZZJJ,W_PZ_NEWDATA.MBDZ,
W_PZ_NEWDATA.YS,SYSDATE,W_PZ_NEWDATA.LRYNO,W_PZ_NEWDATA.MEMO,'0','1'
    FROM W_PZ_NEWDATA
   WHERE :new.JSPBM=W_PZ_NEWDATA.ID;    --如果w_pz表中插入的数据是由新品数据表创建成功的,则写入w_pz_web表中去   


    v_loc := '2.update W_PZ_NEWDATAMODE';
    UPDATE W_PZ_NEWDATAMODE SET
    SAPCODE=:new.SAPCODE,
    DATEMODE='5',
    VALIDDATE=SYSDATE
    WHERE W_PZ_NEWDATAMODE.ID=:new.jspbm;--更新最终状态表的状态


    v_loc := '3.insert w_PZ_NEWDATASTATE';
    INSERT INTO W_PZ_NEWDATASTATE
    (ID,NEWDATAID,DATEMODE,VALIDDATE,CLYNO)
    select w_pz_newdata_seq.nextval,:new.jspbm,'5',SYSDATE,'SAP'
    from W_PZ_NEWDATA  
    WHERE W_PZ_NEWDATA.ID=:new.jspbm;--添加历史状态信息


    v_loc := '4.update w_PZ_lryno';
    v_lryno :='';
    v_num :=0;
    select count(*) into v_num from w_pz_newdata where w_pz_newdata.id=:new.jspbm;
    if (v_num=1) then
    select lryno into v_lryno from w_pz_newdata where w_pz_newdata.id=:new.jspbm;
    v_no := :new.no;
    update w_pz set lryno=v_lryno  where no=v_no;
    end if;--修改自身表,将w_pz_newdata表中的录入人员和折扣更新进w_pz

   

   
    v_loc := '5.delete W_PZ_NEWDATA where w_PZ_NEWDATA.ID=W_PZ.JSPBM';
    DELETE FROM W_PZ_NEWDATA WHERE W_PZ_NEWDATA.ID=:new.JSPBM;--删除此新品数据表w_pz_newdata
    COMMIT;

    exception when others then
    rollback;
    ret := v_loc||'--执行出错! '||sqlerrm; 
    RAISE_APPLICATION_ERROR(-20001,ret);
    end;
end if;
end;
/

程序编译未报错,但修改自身数据表没有成功。

在网上看到一篇文章,介绍用包来做。

关于触发器修改自身数据表实例(转)

2008-09-05 17:23:02| 分类: ORACLE | 标签: |字号 订阅

关于触发器修改自身数据表实例

1 前言
  当然,在触发器修改自身数据表,对于有Oracle数据库后台编程人员来说,并不应该算是一个难题,可能在平时的工作中就经常要遇到。
  但对于刚刚使用ORACLE数据库后台编程人员来说,的确是一个比较烦人的问题。
  
  2 说明
  ORACLE的触发器分为两类:行触发器(For Each Row)和表触发器,在行触发器中,不得将Insert/Update/Delete语句作用于自身数据表;在表触发器中,不得使用:New/:Old语句。
  但在实际编程过程中,我们往往需要对自身数据表进行DML(Insert/Update/Delete)操作,同时引用:New/:Old对象。
  如:使用Insert Into xxx (Select * From yyy Where xKey=123456)语句后,我们需要保存插入记录的时间,由于数据库操作的时间差,我们不可以使用:New.xDate:=SysDate语句 <使用这一语句后,插入的每笔记录xDate的数值会不一样,可相差数秒>。
  对我们来说,最好的语句是:Update xxx Set xDate=SysDate Where xKey=:New.xKey。此时,我们使用Update语句的同时,又使用了:New对象,ORACLE认为不合法。
  
  3 解决提案
  实现此需求,我们需要建立一个行触发器、一个表触发器以及一个程序包。
  
  --3.0 创建测试环境
  Drop Table xxx;
  Drop Table yyy;
  --创建数据表
  Create Table xxx(
    xKey  Number(4),
    xDate  Date,
    xData  number(10));
  Create Table yyy(
    xKey  Number(4),
    xDate  Date,
    xData  number(10));
  
  --3.1 创建程序包,设立全局变量G_xKe
  Create Or Replace Package Pkg_xxx_Update
  as
    G_xKey xxx.xKey%Type;
  End Pkg_xxx_Update;
  /
  --3.2 创建行触发器,并将xKey的值存入程序包的全局变量中
  Create Or Replace Trigger TRG_Upd_xxx_Rec
  After Insert On xxx
  For Each Row
  Begin
    Pkg_xxx_update.G_xKey:=:New.xKey;
  End;
  /
  --3.3 创建表触发器,根据程序包的全局变量,对数据表的xDate字段进行更新
  Create Or Replace Trigger TRG_Upd_xxx_TB
  After Insert On xxx
  Begin
    Update xxx
     set 
       xDate=SysDate 
     Where
       xKey=PKG_xxx_Update.G_xKey;
  End;
  /
  --3.4 插入大量数据
  <>
  Declare 
  L_Count Number:=1;
  Begin
  Delete from yyy;
  While L_Count<100000
  Loop
  insert into yyy
  values(1, SysDate, L_Count);
  L_Count:=L_Count+1;
  End Loop;
  Commit;
  End InsertMultiRecord;
  
  --3.5 测试触发器
  Insert Into xxx
    (Select * from yyy);
  Commit;
  Select * From xxx;

但不太明白,这里的TRG_Upd_xxx_Rec是行触发的,TRG_Upd_xxx_Tb 是表触发,Pkg_xxx_update.G_xKey难道可以存放一个数列,然后到最后一起更新?

后来看到论坛上有一篇文章,讲述的问题,和我的很相似:

对于同一个表t_emp_cde(人员表),我想判断,如果这个员工的部门发生改变c_dpt_cde(部门字段),我就设置其他两个字段为0,触发器我这么写的:
CREATE OR REPLACE TRIGGER TRI$_T_EMP_CDE_CHANGEDEP
BEFORE UPDATE of c_dpt_cde ON T_EMP_CDE FOR EACH ROW
DECLARE
v_emp_cde VARCHAR2(10);
BEGIN
IF UPDATING THEN
v_emp_cde := :NEW.C_EMP_CDE;
IF :NEW.C_DPT_CDE != :OLD.C_DPT_CDE THEN
UPDATE T_EMP_CDE SET NC_STATUS=0 , NC_OPR_STATUS=0
WHERE C_EMP_CDE = v_emp_cde;
END IF;
END IF;
END;
当我执行update语句时报错:
ORA-04091:表T_EMP_CDE发生了变化,触发器/函数不能读 ORA-O6512:在TRI$_T_EMP_CDE_CHANGEDEP LINE 7
我知道可能是变量取值时候发生的错,于是我把触发器作了如下更改;
CREATE OR REPLACE TRIGGER TRI$_T_EMP_CDE_CHANGEDEP
BEFORE UPDATE of c_dpt_cde ON T_EMP_CDE FOR EACH ROW
DECLARE
v_old_emp_cde VARCHAR2(10);
v_new_emp_cde VARCHAR2(10);
BEGIN
v_old_emp_cde:= :old.C_EMP_CDE;
if UPDATING THEN
v_new_emp_cde:= :new.C_EMP_CDE;
IF TRIM(v_new_emp_cde) != TRIM(v_old_emp_cde) THEN
UPDATE T_EMP_CDE SET NC_STATUS= '0 ',NC_OPR_STATUS= '0 ' WHERE C_EMP_CDE = TRIM(v_old_emp_cde);
END IF;
END IF;
END;

这次触发器创建成功,当我执行update语句后没有抱任何错,但我查询NC_OPR_STATUS和NC_STATUS两个字段的时候,发现值没有改变,这是什么原因呢???
。。。

具体的地址:http://topic.csdn.net/t/20060328/13/4645413.html

 

create or replace trigger biufer_w_pz_jspbm 
after insert on w_pz
for each row
declare
v_loc    varchar2(100);    --靠靠靠
ret             VARCHAR2(1000);
v_lryno  varchar2(16);
v_num  NUMBER(4,0);
v_zk01 NUMBER(18,4);
PRAGMA   AUTONOMOUS_TRANSACTION;
begin
--    if  judgedate(SYSDATE)= 0 then
--    begin

    v_loc := '1.insert W_PZ_WEB';
    INSERT INTO W_PZ_WEB 
    (NO,FM,NRJJ,ZZJJ,MBDZ,YS,VALIDDATE,LRYNO,MEMO,DJL,ZDFLAG)
    SELECT  :new.NO,W_PZ_NEWDATA.FM,W_PZ_NEWDATA.NRJJ,W_PZ_NEWDATA.ZZJJ,W_PZ_NEWDATA.MBDZ,
W_PZ_NEWDATA.YS,SYSDATE,W_PZ_NEWDATA.LRYNO,'WEB','0',''
    FROM W_PZ_NEWDATA
    WHERE :new.JSPBM=W_PZ_NEWDATA.ID;    --靠靠靠靠~2_pz_newdata靠靠靠靠?
   


    v_loc := '2.update W_PZ_NEWDATAMODE';
    UPDATE W_PZ_NEWDATAMODE SET
    SAPCODE=:new.SAPCODE,
    DATEMODE='5',
    VALIDDATE=SYSDATE
    WHERE W_PZ_NEWDATAMODE.ID=:new.jspbm;


    v_loc := '3.insert w_PZ_NEWDATASTATE';
    INSERT INTO W_PZ_NEWDATASTATE
    (ID,NEWDATAID,DATEMODE,VALIDDATE,CLYNO)
    select concat(to_char(sysdate,'MMDD'),w_pz_newdata_seq.nextval),:new.jspbm,'5',SYSDATE,'SAP'
    from W_PZ_NEWDATA  
    WHERE W_PZ_NEWDATA.ID=:new.jspbm;


    v_loc := '4.update w_PZ_lryno';
    v_lryno :='';
    v_zk01 :=0;
    v_num :=0;
    select count(*) into v_num from w_pz_newdata where w_pz_newdata.id=:new.jspbm;
    if (v_num=1) then
    select lryno into v_lryno from w_pz_newdata where w_pz_newdata.id=:new.jspbm;
    select zk01 into v_zk01 from w_pz_newdata where w_pz_newdata.id=:new.jspbm;
    :new.lryno := v_lryno;
    :new.zk01 := v_zk01;
    end if;
   
    v_loc := '5.delete W_PZ_NEWDATA where w_PZ_NEWDATA.ID=W_PZ.JSPBM';
    DELETE FROM W_PZ_NEWDATA WHERE W_PZ_NEWDATA.ID=:new.JSPBM;
    COMMIT;

    exception when others then
    rollback;
    ret := v_loc||'--执行出错! '||sqlerrm; 
    RAISE_APPLICATION_ERROR(-20001,ret);
--    end;
--end if;
end;

受启发将程序更新,编译的时候,提示出错大致就是:new在此时不能被更新,上网查找原因

ORA-04084

2010-01-29 01:26:44| 分类: 我的技术 | 标签: |字号 订阅

执行报错,错误信息:ORA-04084 无法更改此触发器类型的NEW值

Oracle Error : ORA-04084

cannot change NEW values for this trigger type

Cause

New trigger variables can only be changed in before row insert or update triggers.

Action

Change the trigger type or remove the variable reference.

after update or after insert 以 New.变量便不能再赋值。

比如 :New.aa :='3333' 是不行的,这个时候操作已经执行完成,不能操作 :New.aa了。

 

因此将

create or replace trigger biufer_w_pz_jspbm
    after insert on w_pz
    for each row

更新为before insert on w_pz

编译通过,星期一回来期待验证结果正确!!!!!

<!-- 正文结束 -->

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/22525676/viewspace-1117060/,如需转载,请注明出处,否则将追究法律责任。

上一篇: 没有了~
下一篇: 没有了~
请登录后发表评论 登录
全部评论

注册时间:2009-09-13