2009-04-24 102 views
3

觸發器內部我試圖遍歷表上的所有列,並將新值與舊值進行比較。以下是我迄今爲止:Oracle PL/SQL:動態循環觸發器列

CREATE OR REPLACE TRIGGER "JOSH".TEST#UPD BEFORE 
UPDATE ON "JOSH"."TEST_TRIGGER_TABLE" REFERENCING OLD AS OLD NEW AS NEW FOR EACH ROW 
declare  
    oldval varchar(2000); 
    newval varchar(2000); 
begin  
    for row in (SELECT column_name from user_tab_columns where table_name='TEST_TRIGGER_TABLE') loop 
    execute immediate 'select :old.'||row.column_name||' from dual' into oldval; 
    execute immediate 'select :new.'||row.column_name||' from dual' into newval; 
    --Do something here with the old and new values 
    end loop; 
end; 

觸發編譯,但是當觸發火災,我越來越:

ORA-01008:並非所有變量綁定

在第一次立即執行,因爲它的值爲:old:old:new已被定義爲觸發器的一部分,但看起來立即執行不能看到這些變量。

是否有辦法動態地迭代觸發器中的列值?

+1

只有在指定觸發器爲FOR EACH ROW時,才能使用舊的和新的關鍵字。 – Powerlord 2009-04-24 17:02:21

+0

正確的是「FOR EACH ROW」。問題是我試圖在動態sql語句中引用它們。 – 2009-04-24 17:04:09

回答

5

不,您不能引用:舊值和新值動態。正如Shane所建議的那樣,您可以編寫代碼來生成靜態觸發器代碼,如果這樣可以讓生活更輕鬆。此外,您還可以「在這裏做什麼」到一個包程序,使您的觸發變爲:

CREATE OR REPLACE TRIGGER JOSH.TEST#UPD BEFORE 
UPDATE ON JOSH.TEST_TRIGGER_TABLE 
begin  
    my_package.do_something_with (:old.col1, :new.col1); 
    my_package.do_something_with (:old.col2, :new.col2); 
    my_package.do_something_with (:old.col3, :new.col3); 
    -- etc. 
end; 

(您可以通過溝的方式毫無意義的REFERENCING子句)。

4

我不確定你是否可以做你想做的事情。你不想在PL/SQL代碼中明確命名錶列的原因是什麼?如果表字段經常發生變化,您可以構建PL/SQL,爲每個表動態構建PL/SQL觸發器(每個表中都有顯式字段名稱)。每次表更改時,都可以運行PL/SQL來生成新的觸發器。

2

我有一個類似的問題,雖然在MSSQL。

我的解決方案是編寫一個存儲過程,它遍歷表和列信息(通過字典視圖或自定義存儲庫)並生成所需的觸發器。該過程只有在數據模型更改時才需要運行。

好處是,您不必在每次更新中通過元模型進行遊標移動,而是提前生成觸發器。

4

你基本上是在嘗試構建自己的系統來審計對錶的所有更改嗎? (我最好猜測你對新舊任意列值的處理方式。)如果是這樣,你可能需要考慮Oracle自己的審計功能。