PL / SQL触发器 - 动态参考:NEW或:OLD

时间:2009-03-26 23:00:29

标签: oracle plsql triggers

是否可以动态引用:NEW / OLD伪记录,或复制它们?

我正在为一个非常宽的表做一个审计触发器,所以我希望避免使用单独的插入/删除/更新触发器。

更新/插入时我想在审计表中记录:NEW值,删除时我想记录:OLD值。

6 个答案:

答案 0 :(得分:3)

创建或替换触发器audit_tgr 在'table_name'上插入或更新或删除之前

for each row
 begin
  if (inserting or updating) then
   insert into audit table (a,b,c) values(:new.a,:new.b,:new.c);
  else
   insert into audit table (a,b,c) values(:old.a,:old.b,:old.c);
end;

答案 1 :(得分:2)

你可以尝试:

declare
  l_deleting_ind varchar2(1) := case when DELETING then 'Y' end;
begin
  insert into audit_table (col1, col2)
  values
   ( CASE WHEN l_deleting_ind = 'Y' THEN :OLD.col1 ELSE :NEW.col1 END
   , CASE WHEN l_deleting_ind = 'Y' THEN :OLD.col2 ELSE :NEW.col2 END
   );
end;

我发现变量是必需的 - 你不能直接在insert语句中访问DELETING。

答案 2 :(得分:2)

哇,你想在你的触发器中只有一个插入物以避免什么?

“我有一个插入语句INSERT INTO HIST(EMP_ID,NAME)VALUES(:NEW.EMP_ID,:NEW.NAME);但删除时,我想使用:OLD,不是没有单独的插入语句。“

这是一张宽大的桌子。所以?它不像文本编辑器中没有REPLACE,你不会再次编写Insert,只需复制,粘贴,选择,替换:NEW with:OLD。

Tony确实有一个解决方案,但我非常怀疑它的性能优于2个插件。

有什么大不了的?


修改

我试图避免的主要事情是在表更改时必须管理2个插入。 - 马修沃森

我一直在与这种态度作斗争。那些编写Java或C ++或.Net的人有一个内置的RBO ...这样做,这很好。不要这样做,这很糟糕。他们根据这些规则编写代码,这很好。问题是这些规则何时应用于数据库。数据库的行为与代码的行为方式不同。

在代码世界中,在两个“地方”中具有基本相同的代码是不好的。我们避免它。可以将该代码抽象为函数并从两个地方调用它,从而避免将其保持两次,并且可能缺少一个,等等。我们都知道这个问题。

在这种情况下,虽然它是 true ,但最后我推荐两个插入,它们由ELSE分隔。你不会改变一个而忘记另一个。 IT就在那里。它不在不同的包中,或在某些已编译的代码中,甚至在同一触发器中的其他位置。他们就在彼此旁边,有一个ELSE,插入重复:NEW,而不是:OLD。为什么我对此如此狂热?这真的有所作为吗?我知道两个插件不会比其他想法更差,它可能会更好。

真正的原因是为它重要的时刻做好准备。如果你只是为了维护而避免使用两个插件,那么你将会错过这种巨大差异的时间。

INSERT INTO log
SELECT * FROM myTable 
WHERE flag = 'TRUE'

ELSE                          -- column omitted for clarity

INSERT INTO log
SELECT * FROM myTable 
WHERE flag = 'FALSE'
包括马修在内的一些人会说这是不好的代码,有两个插入。我可以轻松地用绑定变量替换'TRUE'和'FALSE'并随意翻转它。这就是大多数人会做的事情。但如果True是.1%的值而99.9%是False,则需要两个插入,因为您需要两个执行计划。一个是索引更好,另一个是FTS。所以,是的,你有两个要维护的插入。这并不总是坏事,在这种情况下它是好的和可取的。

答案 3 :(得分:1)

您可以使用复合触发器并以编程方式检查它是否为I / U / D.

Compound Triggers

答案 4 :(得分:0)

为什么不使用Oracle内置的标准或细粒度审核?

答案 5 :(得分:0)

使用复合触发器,正如其他人所建议的那样。将旧值或新值(视情况而定)保存到变量中,并使用insert语句中的变量:

declare
  v_col1  table_name.col1%type;
  v_col2  table_name.col2%type;
begin
  if deleting then
    v_col1 := :old.col1;
    v_col2 := :old.col2;
  else
    v_col1 := :new.col1;
    v_col2 := :new.col2;
  end if;

  insert into audit_table(col1, col2)
  values(v_col1, v_col2);
end;