4

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

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

4 回答 4

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 子句)。

于 2009-04-24T17:25:32.250 回答
4

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

于 2009-04-24T17:08:50.010 回答
4

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

于 2009-04-24T17:29:58.090 回答
2

我有一个类似的问题,虽然在 MSSQL 中。

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

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

于 2009-04-24T17:19:13.123 回答