首页 > 数据库 > Oracle > 关于oracle触发器中修改自身表字段的问题
之前写了一个oracle触发器,两个系统之间通过接口传递数据的时候,当一个表被写入数据时,引发一系列数据表的动作
create or replace trigger biufer_w_pz_jspbm
after insert on w_pz
for each row
declare
PRAGMA
v_loc
ret
v_lryno
v_no
v_num
begin
W_PZ_NEWDATA.YS,SYSDATE,W_PZ_NEWDATA.LRYNO,W_PZ_NEWDATA.MEMO,'0','1'
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
ret
v_lryno
v_num
v_zk01 NUMBER(18,4);
PRAGMA
begin
--
--
W_PZ_NEWDATA.YS,SYSDATE,W_PZ_NEWDATA.LRYNO,'WEB','0',''
--
--end if;
end;
受启发将程序更新,编译的时候,提示出错大致就是:new在此时不能被更新,上网查找原因
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 on
Act
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
更新为before insert on w_pz
编译通过,星期一回来期待验证结果正确!!!!!
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/22525676/viewspace-1117060/ ,如需转载,请注明出处,否则将追究法律责任。