用触发器实现数据关联修改

一、前言

我所在的公司,有的人数据库设计喜欢冗余字段,比如订单中需要存储客户,一般我们只放客户id,但是他不,要把客户名称冗余进去。如果后期来客户名称更改了,这里是需要改过来的。如果用程序来实现同步修改的话,hi比较麻烦。与有的人不喜欢用触发器和存储过程相反,我喜欢用触发器来做这类简单粗暴的事情,简单又不失优雅。N年前,我曾经用存储过程实现过一个接口系统,当时未解决sql server 存储过程递归调用不能超过9层大伤脑筋。这是闲话,下面我们来讲怎么用触发器实现数据的关联修改。

二、配置表

要实现关联修改,首先要知道哪些表引用了哪些表,也就是表与表之间的引用关系,比如上面呢的例子,订单表引用了客户表。这个需要通过一个配置表进行定义。配置表的结构如下:

数据引用关系表:phs_dataref_rel
  说明
1 table_name   引用其他表数据的表的名称,比如上面的订单表
2 fk_col 外键列名称,比如订单中的客户id列
3 fk_name_col   引用数据的名称列,比如订单中的客户名称列
4 fkref_table   引用的表名称,比如上例中的客户表      
5 cond_expr 修改的附件条件,比如只修改当年的数据,历史年度的维持不动
6 enable 本条配置是否生效,可以修改为0,不启用本条配置

举个例子:

insert into phs_dateref_rel( table_name, fk_col, fk_name_col fkref_table ) values( 'sd_order', 'cust_id', 'cust_name', 'md_customer' );

以上的配置信息,定义了 sd_order 订单表的 cust_id 引用了 md_customer 客户表 的id,cust_name 是客户的名称。(本文只处理 id-name 这种简单的引用关系,其他的雷同)。

三、触发器

我们在md_customer上实现一个触发器,当客户名称修改时,同步修改订单表中的客户名称。

 1 create or replace trigger tri_update_ref_name
 2 after update on md_customer
 3 for each row
 4 declare
 5   v$sql varchar2(1000) ;
 6 begin
 7    if updating( 'name') then
 8       for r in( select table_name,fk_col, fk_name_col, cond_expr from phs_fkref_relation where UPPER(fkref_table) = 'MD_CUSTOMER') loop
 9          v$sql :='update '|| r.table_name ||' set '||r.fk_name_col||' =:1 where '||r.fk_col||' = :2';

  10          if ( trim( r.cond_expr ) is not null ) then
  11            v$sql := v$sql + ' and ' || trim( r.cond_expr) ;
  12          1end if ;

13          execute immediate v$sql using :new.name, :new.id;
14       end loop;
15    end if ;
16 end ;

以上触发器的功能是,当客户名称修改时,他会根据配置表,查找所有引用客户名称的表,将表中的客户名称列的值修改为新的值。

四、总结

以上方案实现了,通过触发器修改关联的数据。比较适合的场景是:

存在大量的这种冗余数据,尤其是历史遗留项目,如果通过代码避免这种冗余或实现同步修改会关联数据,付出大量的成本。

局限:

以上方案只处理了通过id-name这种形式,冗余name这种情况。但是举一反三,通过扩展,他也可以期限其他冗余数据的级联更新,比如客户联系信息等等。

其实解决数据不一致的根本举措还是避免滥用冗余,使用冗余要有原则。文中的方案只是一种外挂式的备选方案。

原文地址:https://www.cnblogs.com/senline/p/update_refdata_by_trigger.html