代码之家  ›  专栏  ›  技术社区  ›  Josh Bush

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

  •  4
  • Josh Bush  · 技术社区  · 16 年前

    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 . :new 已被定义为触发器的一部分,但似乎execute immediate看不到这些变量。

    4 回复  |  直到 8 年前
        1
  •  5
  •   Tony Andrews    16 年前

    不,您不能动态引用: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条款)。

        2
  •  4
  •   Shane    16 年前

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

        3
  •  4
  •   Dave Costa    16 年前

    您是否基本上试图构建自己的系统来审核表中的所有更改?(我最好的猜测是,你可能会对任意列的新旧值做些什么。)如果是这样,你可能想研究一下Oracle自己的审计功能。

        4
  •  2
  •   devio    16 年前

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

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

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