用觸發器實現數據關聯修改


一、前言

我所在的公司,有的人數據庫設計喜歡冗余字段,比如訂單中需要存儲客戶,一般我們只放客戶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這種情況。但是舉一反三,通過擴展,他也可以期限其他冗余數據的級聯更新,比如客戶聯系信息等等。

其實解決數據不一致的根本舉措還是避免濫用冗余,使用冗余要有原則。文中的方案只是一種外掛式的備選方案。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM