在更新之前将行复制到历史表而不在PL / SQL触发器中枚举列名?

时间:2015-12-02 16:16:10

标签: oracle plsql triggers oracle12c mutating-table

我正在尝试创建一个PL / SQL触发器,在更新行时将行的当前版本复制到历史记录表中。这可以很容易地完成:

CREATE OR REPLACE TRIGGER foo BEFORE UPDATE ON bar FOR EACH ROW
BEGIN
  INSERT INTO bar_history VALUES bar.id = :old.id, bar.col1 = :old.col1 /* ...and so on */;
END;

但是,我想避免枚举所有列名,因为表barbar_history是相同的,我不想在每次更改表时更新触发器。我尝试过两种方法,但都没有。还有其他方法可以解决这个问题吗?

方法1:

CREATE OR REPLACE TRIGGER foo BEFORE UPDATE ON bar FOR EACH ROW
BEGIN
  INSERT INTO bar_history VALUES :old;
END;

由于您显然无法将:old用作行类型(请参阅this问题),因此出现以下错误消息:

  

PLS-00049:错误的绑定变量' OLD'

方法2:

CREATE TRIGGER foo BEFORE UPDATE ON bar FOR EACH ROW
BEGIN
  INSERT INTO bar_history
  SELECT * FROM bar WHERE id = :old.id;
END;

这也给了我一个错误:

  

ORA-04091:BAR正在变异,触发/功能可能看不到它

3 个答案:

答案 0 :(得分:2)

您需要引用各个列。无法引用触发器中的整行。如果您需要对许多表进行此操作或经常更改表定义,则可以根据数据字典视图编写pl / sql以为您生成触发器。 更新:类似问题/答案:In an Oracle trigger, can I assign new and old to a rowtype variable?

答案 1 :(得分:1)

有些人以前遇到过这种情况。 他们的方法 - 使用包全局变量来存储rowid并在after语句触发器中动态选择列名。 https://community.oracle.com/message/370167

Tom Kyte也对此有一些建议

https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:734825535375 https://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:59412348055

答案 2 :(得分:0)

在这种情况下,您可以使用列表分区策略创建分区表(一个用于当前C和历史H)。您可以创建而不是触发器,在更新表的情况下,将插入记录并将现有记录状态更新为H - 这会隐式地将记录移动到历史分区。