使用Trigger的Oracle动态sql使用:new和:old变量

时间:2013-12-12 17:17:57

标签: oracle plsql

我正在尝试使用all_tab_columns将大型触发器代码简化为简洁代码,因为表包含200列。有些原因在尝试使用动态sql时,它不会让我更新声明的变量。

DECLARE
v_new_rec SOME_TABLE%ROWTYPE;
v_sql VARCHAR(4000);
BEGIN

  SELECT 'v_new_act.' || lower(column_name) || ' := :new.' || lower(column_name)
    INTO v_sql
    FROM all_tab_columns
   WHERE table_name = 'SOME_TABLE'
ORDER BY column_id;

EXECUTE IMMEDIATE v_sql USING v_new_rec;

EXEC my_stored_proc(v_new_rec);

END;
/

任何建议???

2 个答案:

答案 0 :(得分:3)

这种方法不起作用,也不起作用。您无法动态引用:new:old伪记录。

如果您想沿着这条路走下去,您实际上想要编写生成触发器的动态SQL,而不是触发器中的动态SQL。有些东西(显然是未经测试的)

l_sql := 'CREATE OR REPLACE TRIGGER trg_' || l_table_name ||
         '  BEFORE INSERT ON ' || l_table_name ||
         '  FOR EACH ROW ' ||
         'DECLARE ' ||
         '  l_rec ' || l_table_name || '%ROWTYPE' ||
         'BEGIN ';
for cols in (select * from all_tab_cols where table_name = l_table_name)
loop
  l_sql := l_sql || ' l_rec.' || cols.column_name || 
                       ' = :new.' || cols.column_name || ';';
end loop;
...

或者,如果要根据对象类型声明表,:new:old将是对象类型的实际实例,然后可以将其传递给存储过程。

答案 1 :(得分:2)

你不能这样做:变量:new和:old超出了动态SQL的范围。

你也不能把它作为rowtype / Oracle类型 - 我尝试过多次不同的事情。

您可以做的一切 - 动态生成完整的触发器代码。我是为触发器做的,它将所有的东西重新加载到表数据更改的历史表中。

就你的触发器的大小而言(如果它的长度超过32767字节)你应该使用dbms_sql包而不是立即执行