2016-11-04 43 views
0

在另一個question我試圖創建一個hist表,它保留給定表的日誌。隨着這個問題的答案,我試圖創造新的東西。user_tab_columns何時更新?

因爲它是不可能創建表或視圖系統觸發,我創建了一個DDL觸發器是這樣的:

create or replace trigger ident_hist_trig after alter on schema 
declare 
    v_table varchar2(30); 
begin 
    select upper(ora_dict_obj_name) into v_table from dual; 
    if (v_table = 'Z_IDENT') then 
     prc_create_hist_tabel('z_ident_hist', 'z_ident'); 
    elsif (v_table = 'D_IDENT') then 
     prc_create_hist_tabel('d_ident_hist', 'd_ident'); 
    elsif (v_table = 'X_IDENT') then 
     prc_create_hist_tabel('x_ident_hist', 'x_ident'); 
    else 
     null; 
    end if; 
end; 
/

過程prc_create_hist_tabel看起來是這樣的:

create or replace procedure prc_create_hist_tabel(p_naam_hist_tabel in varchar2, p_naam_tabel in varchar2) is 
    cursor c is 
     select 'alter table ' || p_naam_hist_tabel || ' add ' || column_name || ' ' || data_type || case when data_type = 'DATE' then null else '(' || data_length || ')' end lijn 
     from user_tab_columns 
     where TABLE_NAME = upper(p_naam_tabel) 
     and column_name not in (select column_name from user_tab_columns where table_name = upper(p_naam_hist_tabel)); 
    v_dummy number(1); 
    cursor trig is 
     select column_name || ',' kolom, ':old.' || column_name || ',' old 
     from user_tab_columns 
     where table_name = upper(p_naam_tabel); 
    v_trigger_sql varchar2(32767); 
begin 
    begin 
     select 1 into v_dummy 
     from user_tab_columns 
     where TABLE_NAME = upper(p_naam_hist_tabel) 
     group by 1; 
    exception when no_data_found then 
     execute immediate 'create table ' || p_naam_hist_tabel || ' (wijziger varchar2(60) default user, wijzigdatum date default sysdate, constraint pk_' || p_naam_hist_tabel || ' primary key (wijziger, wijzigdatum))'; 
    end; 
    dbms_output.put_line('BBB'); 
    for i in c 
    loop 
     begin 
      dbms_output.put_line(i.lijn); 
      execute immediate i.lijn; 
     exception when others then 
      dbms_output.put_line(i.lijn); 
     end; 
    end loop; 

    v_trigger_sql := 'create or replace trigger ' || p_naam_tabel || '_hist_trig after update on ' || p_naam_tabel || ' for each row begin insert into ' || p_naam_hist_tabel || ' ('; 
    for v_lijn in trig 
    loop 
     v_trigger_sql := v_trigger_sql || v_lijn.kolom; 
    end loop; 
    v_trigger_sql := substr(v_trigger_sql, 1, length(v_trigger_sql) - 1); 
    v_trigger_sql := v_trigger_sql || ') values ('; 
    for v_lijn in trig 
    loop 
     v_trigger_sql := v_trigger_sql || v_lijn.old; 
    end loop; 
    v_trigger_sql := substr(v_trigger_sql, 1, length(v_trigger_sql) - 1); 
    v_trigger_sql := v_trigger_sql || '); end;'; 

    execute immediate v_trigger_sql; 
end; 
/

總之該功能所做的是維護歷史表。如果它不存在,它將創建一個,如果它存在,它會將新列添加到它。該過程還會創建一個新的觸發器,它將在更新後將舊值寫入歷史記錄表中。

但是,當我改變表x_ident,z_ident或d_ident之一,光標C將返回什麼(我可以檢查與打印時,我環路通過它)。雖然在之後執行選擇我改變了我的表格,但我確實得到了結果。

我從改變表d_ident得到的結果是這些:

BBB 

d_ident: Table altered. 

但我想它應該是周圍的其他方式,我認爲ALTER TABLE居然熄滅之前執行的程序prc_create_hist_tabel,我想我應該得到這樣的東西:

d_ident: Table altered. 

BBB 

任何幫助將被apreciated。我試圖在user_tab_columns上插入時創建一個觸發器,但是這給了我ORA-25001:無法在視圖上創建此觸發器類型。

我有休眠命令嘗試爲好,但也不能工作。

回答

1

這是行不通的。即使你能夠獲得添加到觸發器表中的列,如果你試圖在觸發器中實際執行DDL,你會得到一個DDL不允許觸發的錯誤。

我期望解決這個正確的方法是撥打電話到prc_create_hist_tabel作爲促進腳本的一部分。合理的系統不會無處不在列地添加列。 DDL是源代碼控制中存在的促銷活動的一部分,並在測試後部署。如果您的升級腳本無法修改歷史記錄表,您會在測試過程中發現您錯過了一個步驟,並且更改永遠不會投入生產。自動發生變化意味着它們沒有處於變更控制中,這使得從變更控制進行構建變得更加困難。

如果您決定自動執行該操作,則需要使用dbms_job而不是較新的dbms_scheduler來提交作業,您的觸發器需要提交作業。該作業將在事務之後運行,DDL觸發器是提交的一部分。此時,該列將在dba_tab_columns中可見。你的工作可以自由地執行DDL。