Reputation: 8577
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
Upvotes: 1
Views: 2857
Reputation: 2805
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
Upvotes: 1
Reputation: 18685
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?
Upvotes: 2
Reputation: 3956
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.
Upvotes: 0