2012-03-26 8 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

+0

Oracle 10gを使用しています –

答えて

1

1つのオプション:論理をプッシュして、列がf_logプロシージャにトラッキングされていることを確認し、すべての列を渡します。例えば

、あなたのtrack_Tableは、あなたがこの

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; 

そして善酒、大文字、あなたの内の値のようなものをtrackmしたい各列について(TABLE_NAME、COLUMN_NAME、許可)の値を保持している場合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

いいえ、あなたは動的OLDとNEW疑似変数にアクセスすることはできません。 TRACK_CHANGESテーブルの変更のデータがあなただけの再生成のトリガーに持っているのであれば

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_tableデータを使用しています。

+0

私はトリガーを再生成したくない、それがポイントです。私はテーブルを変更してもトリガーを再生成したくない。 –

+1

私はあなたがしたくないことを感謝します - しかし、私はあなたに他の選択肢がないことを示唆しています! –

関連する問題