两个关联表间如何建立触发器

来源:互联网 发布:worth it舞蹈教学 编辑:程序博客网 时间:2024/06/03 21:09


实现功能描述:
       表C由表A、表B关联生成(其中表A、表B在物理库中,表C在内存数据库中),表A、表B数据变化后通过触发器将变化后记录插入到小表C_inc中,通过小表触发,最后用内存库的实时同步功能将C_inc小表中的记录同步到内存库表C中。

 

问题描述:
      如何将表A、表B变化后的数据插入到小表C_inc中

 

最初实现方案:
      在物理库建立表A、表B关联的视图C_view,然后在视图C_view上建立触发器,通过视图上的触发器将表的变化数据触发到小表C_inc中。

 

遇到的问题
视图上怎么建立触发器?
    

     通过查资料,在视图上建立的触发器为替代触发器,其与DML触发器不同,DML触发器是在DML操作之外运行的,而替代触发器则代替激发它的DML语句运行,代替触发器是行一级的。
替代触发器的用途:
1、允许对无法变更的视图进行修改,视图修改后触发基表数据修改
2、修改视图中嵌套表列的列
例:
create trigger ClassRoomInsert
instead of insert on class_room
declare
v_rooid rooms.room_id%TYPE;
begin
select room_id
into v_roomid
from rooms
where building = :new.building
and room_number = :new.room_number;

set room_id = v_roomid
where department = :new.department
and course = :new.course;
end;
经上所述,替代触发器实现的是允许无法变更的视图进行修改,而不是我想要的基表变化了,视图随之更新,根据视图的更新插入小表C_inc中记录。

 

第二种实现方案:
在触发器中进行2个表数据的关联,触发器如下:
CREATE OR REPLACE TRIGGER t_mmdb_on_balance_type
after insert or update on balance_type_attr
for each row
declare
begin
    if inserting then
            insert into mmdb_balance_type_inc(op_sn,op_type,op_time,BALANCE_TYPE_ID,BALANCE_TYPE_ATTR,ACCT_ITEMS,PRIORITY,CYCLE_UPPER_TYPE,CYCLE_UPPER,CYCLE_LOWER_TYPE,CYCLE_LOWER,PAYMENT_LIMIT_TYPE,PAYMENT_LIMIT)
            select 0,'1',sysdate,a.BALANCE_TYPE,a.BALANCE_TYPE_ATTR,a.ACCT_ITEMS,b.PRIORITY,a.CYCLE_UPPER_TYPE,
            a.CYCLE_UPPER,a.CYCLE_LOWER_TYPE,a.CYCLE_LOWER,a.PAYMENT_LIMIT_TYPE,a.PAYMENT_LIMIT
            from BALANCE_TYPE_ATTR a,bss_acctbook_info b
            where a.BALANCE_TYPE = b.acctbooktype
            and a.BALANCE_TYPE = :new.BALANCE_TYPE;
    elsif updating then
            insert into mmdb_balance_type_inc(op_sn,op_type,op_time,BALANCE_TYPE_ID,BALANCE_TYPE_ATTR,ACCT_ITEMS,PRIORITY,CYCLE_UPPER_TYPE,CYCLE_UPPER,CYCLE_LOWER_TYPE,CYCLE_LOWER,PAYMENT_LIMIT_TYPE,PAYMENT_LIMIT)
            select 0,'2',sysdate,a.BALANCE_TYPE,a.BALANCE_TYPE_ATTR,a.ACCT_ITEMS,b.PRIORITY,a.CYCLE_UPPER_TYPE,
            a.CYCLE_UPPER,a.CYCLE_LOWER_TYPE,a.CYCLE_LOWER,a.PAYMENT_LIMIT_TYPE,a.PAYMENT_LIMIT
            from BALANCE_TYPE_ATTR a,bss_acctbook_info b
            where a.BALANCE_TYPE = b.acctbooktype
            and a.BALANCE_TYPE = :new.BALANCE_TYPE;
    end if;
end;

 

更新数据时报如下错误:
   ORA-04091: table OCSBILLTEST.BALANCE_TYPE_ATTR is mutating, trigger/function may not see it
   ORA-06512: at "OCSBILLTEST.T_MMDB_ON_BALANCE_TYPE", line 11
   ORA-04088: error during execution of trigger 'OCSBILLTEST.T_MMDB_ON_BALANCE_TYPE'
基本意思是在是因为在TRIGGER中访问了变化表所引起的,ORACLE资料上说如INSERT语句仅影响一个行,触发器不把触发表当作变化表处理,也就是在trigger里面不要再访问trigger所在的表了。


修改后的实现方案:
在基表表A、表B上建立触发器,触发器上使用游标操作,进行2个表的关联操作,触发器如下:
CREATE OR REPLACE TRIGGER t_mmdb_on_balance_type
after insert or update on balance_type_attr
for each row
declare
    cursor c_priority is
      SELECT priority FROM BSS_ACCTBOOK_INFO where ACCTBOOKTYPE = :new.BALANCE_TYPE;
begin
 if inserting then
  for v_record in c_priority loop
         insert into mmdb_balance_type_inc(op_sn,op_type,op_time,BALANCE_TYPE_ID,BALANCE_TYPE_ATTR,ACCT_ITEMS,PRIORITY,CYCLE_UPPER_TYPE,CYCLE_UPPER,CYCLE_LOWER_TYPE,CYCLE_LOWER,PAYMENT_LIMIT_TYPE,PAYMENT_LIMIT)
         values(0,'1',sysdate,:new.BALANCE_TYPE,:new.BALANCE_TYPE_ATTR,:new.ACCT_ITEMS,v_record.priority,:new.CYCLE_UPPER_TYPE,
         :new.CYCLE_UPPER,:new.CYCLE_LOWER_TYPE,:new.CYCLE_LOWER,:new.PAYMENT_LIMIT_TYPE,:new.PAYMENT_LIMIT);
     end loop;
 elsif updating then
     for v_record in c_priority loop
         insert into mmdb_balance_type_inc(op_sn,op_type,op_time,BALANCE_TYPE_ID,BALANCE_TYPE_ATTR,ACCT_ITEMS,PRIORITY,CYCLE_UPPER_TYPE,CYCLE_UPPER,CYCLE_LOWER_TYPE,CYCLE_LOWER,PAYMENT_LIMIT_TYPE,PAYMENT_LIMIT)
         values(0,'2',sysdate,:new.BALANCE_TYPE,:new.BALANCE_TYPE_ATTR,:new.ACCT_ITEMS,v_record.priority,:new.CYCLE_UPPER_TYPE,
         :new.CYCLE_UPPER,:new.CYCLE_LOWER_TYPE,:new.CYCLE_LOWER,:new.PAYMENT_LIMIT_TYPE,:new.PAYMENT_LIMIT);
     end loop;
 end if;
end;

由于自己在SQL方面知识比较欠缺,造成建一个关联表的触发器用了4个多小时,还好最后成功的解决了问题,将这之间遇到的问题及解决办法整理了一下,希望能对有同样困扰的人有所帮助。

 

原创粉丝点击