2012-03-26 60 views
1

我想知道我是否可以使用OLD和NEW對象進行觸發器內的動態操作。使用OLD和NEW對象進行觸發器內部的動態操作

我所尋找的是這樣的: -

  1. ABC是,我需要寫觸發器的表。
  2. TracK_Table維護需要跟蹤(記錄)的表的列的列表。
  3. f_log是一個將數據更改插入到跟蹤(日誌)表中的函數。

    CREATE OR REPLACE TRIGGER trg_TRACK 
    AFTER INSERT OR UPDATE OR DELETE ON ABC 
    FOR EACH ROW 
    declare 
        v_old_val varchar2(1000); 
        v_new_val varchar2(1000); 
        n_ret int; 
        n_id varchar(50); 
    
        cursor cur_col is 
        SELECT COLUMN_NAME, 
         TABLE_name  
        FROM track_TABLE 
        WHERE upper(TABLE_NAME) = upper('ABC') 
         AND exists (select cname 
            from col 
            where UPPER(tname) =upper('ABC') 
            and upper(cname)=upper(COLUMN_NAME)) 
         AND upper(allow) = 'Y'; 
    
    begin 
        n_id:= :old.id; 
    
        for i_get_col in c_get_col 
        loop 
         execute immediate 
         'begin 
          :v_old_val:= select '||i_get_col.column_name ||' 
              from '||:old ||' 
              where id = '||n_id ||'; 
          end;' using out v_old_val; 
         execute immediate 
          'begin 
          :v_new_val:= select '||i_get_col.column_name ||' 
              from '||:new ||' 
              where id = '||n_id ||'; 
          end;' using out v_new_val; 
         n_ret := f_log(n_id,i_get_col.column_name,v_old_val,v_new_val); 
        end loop; 
    end; 
    /
    
+0

您使用的是哪個Oracle版本? – Ben 2012-03-26 12:33:16

+0

正在使用Oracle 10g – 2012-03-28 06:56:37

回答

1

一個選項:推動邏輯以檢查列是否正在跟蹤到f_log過程中,然後遍歷所有列。

例如,如果您track_Table持有(表名,列名,允許)的每一列要trackm那麼像這樣

CREATE OF REPLACE PROCEDURE f_log( p_id   varchar2 
            ,p_table_name varchar2 
            ,p_column_name varchar2 
            ,p_old_val  varchar2 
            ,p_new_val  varchar2) 
as 
    l_exists number; 
    cursor chk_column_track IS 
     SELECT 1 
     FROM track_TABLE   
     WHERE upper(TABLE_NAME) = upper(p_table_name)    
     AND  UPPER(column_name) = upper(p_column_name) 
     AND  upper(allow) = 'Y'; 
begin 
    open chk_column_track; 
    fetch chk_column_track into l_exists; 
    if chk_column_track%found then 
     --do the insert here 
    end if; 
    close chk_column_track; 
end; 
/

CREATE OR REPLACE TRIGGER trg_TRACK 
AFTER INSERT OR UPDATE OR DELETE ON ABC 
FOR EACH ROW 
DECLARE 
     n_id varchar(50); 
BEGIN 
    n_id := NVL(:old.id, :new.id); 
    -- send all of the values to f_log and have it decide whether to save them 
    f_log(:old.id,'COL1',:old.col1,:new.col1); 
    f_log(:old.id,'COL2',:old.col2,:new.col2); 
    f_log(:old.id,'COL3',:old.col3,:new.col3); 
    ... 
END; 

而且老天爺,大寫的值值的插入的track_table,以便您不必UPPER()存儲的值,從而使這些值的任何索引無用!

現在,這將咀嚼檢查每個操作的每個列名稱的一些資源,但是如果您沒有運行大容量,那麼它可能是可管理的。

否則,您將需要更優雅的解決方案。就像利用集合的強大功能和TABLE()子句在批量操作中執行track_table查找一樣。請記住,我現在遠離我的數據庫,所以我沒有測試編譯此代碼。

CREATE OR REPLACE TYPE t_audit_row AS OBJECT (
    p_table_name varchar2(30) 
    ,p_column_name varchar2(30) 
    ,p_id   varchar2(50) 
    ,p_old_val  varchar2(2000) 
    ,p_new_val  varchar2(2000) 
); 

CREATE OR REPLACE TYPE t_audit_row_table AS TABLE OF t_audit_row; 

CREATE OR REPLACE PROCEDURE f_log (p_audit_row_table t_audit_Row_table) 
AS 
begin 
    -- see how we can match the contents of the collection to the values 
    -- in the table all in one query. the insert is just my way of showing 
    -- how this can be done in one bulk operation. Alternately you could make 
    -- the select a cursor and loop through the rows to process them individually. 
    insert into my_audit_log (table_name, column_name, id, old_val, new_val) 
    select p_table_name 
      ,p_column_name 
      ,p_id 
      ,p_old_val 
      ,p_new_val 
    FROM track_TABLE TT 
     ,table(p_audit_row_table) art 
    WHERE tt.TABLE_NAME = art.p_table_name      
    AND tt.column_name = art.p_column_name   
    AND tt.allow  = 'Y'; 
end; 
/

CREATE OR REPLACE TRIGGER trg_TRACK 
AFTER INSERT OR UPDATE OR DELETE ON ABC 
FOR EACH ROW 
DECLARE   
    l_id   varchar(50); 
    l_audit_table t_audit_row_table; 
BEGIN   
    l_id := NVL(:old.id, :new.id);   
    -- send all of the values to f_log and have it decide whether to save them 
    l_audit_table := t_audit_row_table (
         t_audit_row ('ABC','COL1',l_id, :old.col1, :new.col1) 
         ,t_audit_row ('ABC','COL2',l_id, :old.col2, :new.col2) 
         ,t_audit_row ('ABC','COL3',l_id, :old.col3, :new.col3) 
         ,... 
         ,t_audit_row ('ABC','COLn',l_id, :old.coln, :new.coln) 
        ); 
    f_log(l_audit_table); 
end; 
/
1

不,你不能訪問舊與新的僞變量動態。你可以做的是使用你的track_table數據的腳本或程序來生成看起來像靜態觸發器:

CREATE OR REPLACE TRIGGER trg_TRACK 
AFTER INSERT OR UPDATE OR DELETE ON ABC 
FOR EACH ROW 
DECLARE 
    n_id varchar(50); 
BEGIN 
    n_id := NVL(:old.id, :new.id); 
    f_log(:old.id,'COL1',:old.col1,:new.col1); 
    f_log(:old.id,'COL3',:old.col3,:new.col3); 
    ... 
END; 

所以,如果在TRACK_CHANGES表中的數據發生變化,你只需要重新生成觸發器。

+0

我不想重新生成觸發器,這是重點。即使改變表格,我也不想重新生成觸發器。 – 2012-03-27 04:28:12

+1

我欣賞你不想 - 但我建議你別無選擇! – 2012-03-27 09:15:28

相關問題