1

I am trying to create a PL/SQL trigger that copies the current version of a row into a history table when the row is updated. This can be easily done like this:

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;

However, I would like to avoid enumerating all the column names since the tables bar and bar_history are identical and I don't want to update the trigger every time I change the table. I have tried two approaches, none of which are working. Is there any other way to solve this?

Approach 1:

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

Since you apparently can not use :old as a rowtype (see this question) I get the following error message:

PLS-00049: bad bind variable 'OLD'

Approach 2:

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

This also gives me an error:

ORA-04091: BAR is mutating, trigger/function may not see it

4

3 回答 3

2

You need to reference the individual columns. There is no way to reference the entire row in the trigger. If you need this for many tables or your table definition changes frequently, you could write pl/sql based on the data dictionary views to generate the trigger for you. Update: Similar question/answer here: In an Oracle trigger, can I assign new and old to a rowtype variable?

于 2015-12-02T16:56:31.883 回答
1

Some people have run into this situation before. Their approach - use package global variables to store rowid and dynamically select column names in after statement trigger. https://community.oracle.com/message/370167

Tom Kyte also has some advice on this

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

于 2015-12-02T17:08:57.127 回答
0

In this case you can create partition table using list partitioning strategy (one for current C and history H). You can create instead of trigger, in case of update of the table, record will be inserted and existing record status will be updated to H - which implicitly move the record to historical partition.

于 2015-12-02T16:43:02.233 回答