【发布时间】:2010-10-15 19:56:46
【问题描述】:
是否可以动态引用 :NEW/OLD 伪记录,或者复制它们?
我正在为一个非常宽的表执行审核触发器,因此希望避免为插入/删除/更新设置单独的触发器。
更新/插入时我想在审计表中记录 :NEW 值,删除时我想记录 :OLD 值。
【问题讨论】:
是否可以动态引用 :NEW/OLD 伪记录,或者复制它们?
我正在为一个非常宽的表执行审核触发器,因此希望避免为插入/删除/更新设置单独的触发器。
更新/插入时我想在审计表中记录 :NEW 值,删除时我想记录 :OLD 值。
【问题讨论】:
为什么不使用 Oracle 内置的标准或细粒度审计?
【讨论】:
您可以使用复合触发器并以编程方式检查它是否为 I/U/D。
【讨论】:
你可以试试:
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;
我发现该变量是必需的 - 您不能在插入语句中直接访问 DELETING。
【讨论】:
哇,您只想在触发器中插入一个来避免什么?
“我有一个插入语句 INSERT INTO HIST (EMP_ID, NAME ) VALUES (:NEW.EMP_ID , :NEW.NAME ) ;但在删除时,我想使用 :OLD ,而不是单独的为此插入语句。"
这是一张宽大的桌子。所以?并不是说文本编辑器中没有 REPLACE,您不会再编写 Insert,只需复制、粘贴、选择、将 :NEW 替换为 :OLD。
Tony 确实有一个解决方案,但我严重怀疑其性能是否优于 2 次插入。
有什么大不了的?
编辑
我要避免的主要事情是在表更改时必须管理 2 次插入。 ——马修·沃森
我一直在与这种态度作斗争。那些编写 Java 或 C++ 或 .Net 的人有一个内置的 RBO……这样做,这很好。不要那样做,那样不好。他们根据这些规则编写代码,这很好。问题是这些规则何时应用于数据库。数据库的行为方式与代码不同。
在代码世界中,在两个“地方”拥有本质上相同的代码是不好的。我们避免它。可以将该代码抽象为一个函数并从两个位置调用它,从而避免对其进行两次维护,并且可能会丢失一个,等等。我们都知道这个练习。
在这种情况下,虽然 true 最后我推荐了两个插入,但它们由 ELSE 分隔。你不会改变一个而忘记另一个。 就在那儿。它不在不同的包中,不在某些已编译的代码中,甚至不在同一个触发器中的其他地方。它们就在彼此旁边,有一个 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'
包括 Matthew 在内的一些人会说这是糟糕的代码,有两个插入。我可以很容易地用绑定变量替换 'TRUE' 和 'FALSE' 并随意翻转它。这就是大多数人会做的事情。但是如果 True 是 0.1% 的值并且 99.9% 是 False,那么您需要两个插入,因为您需要两个执行计划。一个更好用一个索引,另一个用 FTS。所以,是的,您确实需要维护两个插入。这并不总是坏事,在这种情况下它是好的和可取的。
【讨论】:
按照其他人的建议,使用复合触发器。根据需要将旧值或新值保存到变量中,并在插入语句中使用变量:
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;
【讨论】:
创建或替换触发器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;
【讨论】: