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 插入大量数据
<<InsertMultiRecord
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;