Oracle使用insert触发器遇到的问题及解决
作者:世间所有相遇都是久别重逢
在数据库管理中,触发器是重要的工具,用于实现自动化操作和数据完整性维护,本文以一个实际案例详解触发器的基本语句和应用,在导入个人信息时,如果已存在该信息且需更新非导入项(如疫情信息),触发器通过比较:new与:old属性值实现自动同步
Oracle使用insert触发器遇到的问题
首先TRIGGER基本语句
create or replace trigger 'trigger_name'--触发器名称 before insert --或 after insert (触发时机) --关键字before和after用于标识触发时间,顾名思义,before代表触发器里面的命令在DML修改数据之前执行, --after代表触发器里面的命令在DML修改数据之后执行。 REFERENCING new as new --或old as old (用于触发器中参数使用) --注:before中的new指的是当前插入的集,after中的old指的是当前插入的集 FOR EACH ROW --指当前触发器为行级触发器(行级触发器相对于语句级触发器) --行级触发器能够通过 :new.属性 和 :old.属性等获得update或者insert发生之前的新值和发生值之后的旧值。 declare --声明变量…… BEGIN END;
关于行级触发器的 :new.属性 和 :old.属性使用
TRIGGER TONGBUJIAYI_SFZH before DELETE OR UPDATE of D_SFZH ON T_DA_JKDA_RKXZL REFERENCING NEW AS NEW OLD AS OLD FOR EACH ROW BEGIN IF UPDATING THEN insert into T_DA_JKDA_RKXZL_GWANDJY(ID,D_GRDABH,P_RGID,D_SFZH,D_SFZHXGQ,D_DATZXGH,D_XM,D_BGSJ,D_BGZT) VALUES (SYS_GUID(),:OLD.D_GRDABH,:OLD.P_RGID,:OLD.D_SFZH,:NEW.D_SFZH,'',:OLD.D_XM,sysdate,'2'); ELSIF DELETING THEN insert into T_DA_JKDA_RKXZL_GWANDJY(ID,D_GRDABH,P_RGID,D_SFZH,D_SFZHXGQ,D_DATZXGH,D_XM,D_BGSJ,D_BGZT) VALUES (SYS_GUID(),:OLD.D_GRDABH,:OLD.P_RGID,:OLD.D_SFZH,'','',:OLD.D_XM,sysdate,'1'); END IF; END;
在Oracle中执行DML语句的时候是需要显示进行提交操作的。
当我们进行插入的时候,会触发触发器执行对触发器作用表和扩展表的种种操作,
但是这个时候触发器和插入语句是在同一个事务管理中的,因此在插入语句没有被提交的情况下,我们无法对触发器作用表进行其他额外的操作。
如果执行其他额外的操作则会抛出如下异常信息。
ORA-04091:表*****发生了变化触发器/函数不能读它
此次触发器产生场景:
一个身份证号及个人信息导入到系统中,在系统中修改了关于疫情的信息。
但再次导入此人的信息时(每次导入的信息都不包含关于疫情的信息),则需要同步。
由此引入触发器,触发条件为insert
TRIGGER DETECTION_USERS_SYN_VACCINE BEFORE INSERT ON DETECTION_USERS REFERENCING new as new FOR EACH ROW DECLARE --oracle中声明多个属性时只需要用一次DECLARE即可 V_ID DETECTION_USERS.ID%TYPE;--此处声明的属性是按照DETECTION_USERS表中的属性声明 V_IS_VACCINATION DETECTION_USERS.IS_VACCINATION%TYPE; V_VACCINE1 DETECTION_USERS.VACCINE1%TYPE; V_VACCINE2 DETECTION_USERS.VACCINE2%TYPE; V_VACCINE3 DETECTION_USERS.VACCINE3%TYPE; V_NUM_VACCINATION DETECTION_USERS.NUM_VACCINATION%TYPE; --声明游标查询此人添加之前的接种信息 CURSOR latests is SELECT ID, IS_VACCINATION, VACCINE1, VACCINE2, VACCINE3, NUM_VACCINATION FROM (SELECT t.*, row_number() over(order by nvl(zdrq, '0') DESC) rn from (SELECT * FROM (SELECT ID, IS_VACCINATION, VACCINE1, VACCINE2, VACCINE3, NUM_VACCINATION, (CASE WHEN (VACCINE3 IS NOT null) THEN VACCINE3 WHEN (VACCINE2 IS NOT null) THEN VACCINE2 WHEN (VACCINE1 IS NOT null) THEN VACCINE1 ELSE '' END) AS zdrq FROM DETECTION_USERS WHERE "IDENTITY" = :new."IDENTITY" AND IS_VACCINATION IS NOT NULL)) t) WHERE rn = 1; BEGIN OPEN latests; FETCH latests INTO V_ID, V_IS_VACCINATION, V_VACCINE1, V_VACCINE2, V_VACCINE3, V_NUM_VACCINATION; ---打印语句 -- DBMS_OUTPUT.PUT_LINE('latests===' || V_ID || '**' || V_IS_VACCINATION || '**' || -- V_VACCINE1 || '**' || V_VACCINE2 || '**' || -- V_VACCINE3 || '**' || V_NUM_VACCINATION); -- DBMS_OUTPUT.PUT_LINE('new===' || :new.ID || '**' || :new.IS_VACCINATION || '**' || -- :new.VACCINE1 || '**' || :new.VACCINE2 || '**' || -- :new.VACCINE3 || '**' || :new.NUM_VACCINATION); IF INSERTING THEN :new.IS_VACCINATION := V_IS_VACCINATION;--将打开的cursor赋值到新插入的这列数值中 :new.VACCINE1 := V_VACCINE1; :new.VACCINE2 := V_VACCINE2; :new.VACCINE3 := V_VACCINE3; :new.NUM_VACCINATION := V_NUM_VACCINATION; END IF; --FETCH NEXT FROM from_inserted INTOV_ID,V_IS_VACCINATION,V_VACCINE1,V_VACCINE2, V_VACCINE3,V_NUM_VACCINATION; --循环,此处cursor只有一条,不需要。 CLOSE latests; END;
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。