Oracle PL / SQL:动态循环触发器列

时间:2009-04-24 16:54:52

标签: oracle dynamic plsql database-trigger

在触发器内部,我试图遍历表格上的所有列,并将新值与旧值进行比较。以下是我到目前为止的情况:

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已被定义为触发器的一部分,但似乎执行立即数无法看到这些变量。

有没有办法动态迭代触发器中的列值?

4 个答案:

答案 0 :(得分:5)

不,你不能动态引用:old和:new值。正如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条款)。

答案 1 :(得分:4)

我不确定你是否可以做你想做的事。您不希望在PL / SQL代码中明确命名表列的原因是什么?如果表字段经常更改,您可以构建PL / SQL,为每个表动态构建PL / SQL触发器(每个表中都有显式字段名)。每次表更改时,您都可以运行该PL / SQL以生成新的触发器。

答案 2 :(得分:4)

您实际上是在尝试构建自己的系统来审核对表的所有更改吗? (我最好猜测你可能对任意列的旧值和新值做了什么。)如果是这样,你可能想要研究Oracle自己的审计功能。

答案 3 :(得分:2)

我遇到了类似的问题,尽管在MSSQL中。

我的解决方案是编写一个存储过程,该过程遍历表和列信息(通过字典视图或自定义存储库)并生成所需的触发器。只有在数据模型发生变化时才需要运行该过程。

优点是您不必在每次更新中浏览元模型,而是提前生成触发器。