I have three tables: A and B
The relationship is A can have many B
So B has a reference to the A.id as one of its columns
Table A
|id|date|...
Table B
|id|A_id|...
I have created an Oracle trigger on table A so that when it is updated it updates an A_Mod table.
This trigger is
CREATE OR REPLACE TRIGGER TR_A_INSERT_UPDATE
AFTER INSERT OR UPDATE ON A
FOR EACH ROW
BEGIN
INSERT INTO A_Mod values(..., :new.date, ...)
END;
This works fine 🙂
My problem si creating the trigger for table B.
The trigger is:
CREATE OR REPLACE TRIGGER TR_B_INSERT_UPDATE
AFTER INSERT OR UPDATE ON B
FOR EACH ROW
DECLARE
ts TIMESTAMP;
BEGIN
SELECT aa.date INTO ts FROM B bb
INNER JOIN A aa ON a.id = bb.A_id
WHERE bb.id = :new.id;
INSERT INTO A_Mod values(..., :new.date, ...)
END;
This trigger is reading the ID of the updated line in table B and then getting the date from the corresponding row in table A. It then tries to insert it into A_Mod
The problem is I get a mutating error
Error report:
SQL Error: ORA-04091: table B is mutating, trigger/function may not see it
ORA-06512: at "TR_B_INSERT_UPDATE", line 5
ORA-04088: error during execution of trigger 'TR_B_INSERT_UPDATE'
04091. 00000 - "table %s.%s is mutating, trigger/function may not see it"
*Cause: A trigger (or a user defined plsql function that is referenced in
this statement) attempted to look at (or modify) a table that was
in the middle of being modified by the statement which fired it.
*Action: Rewrite the trigger (or function) so it does not read that table.
Looking at the docs I can remove this error by removing the FOR EACH ROW line and having the trigger fire once per statement rather than once per row. Unfortunately I am using an ORM mapper so do not control how the updates happen. I think there would be times when the update could cover multiple rows.
The docs say something about creating a temporary table but I am not sure how this would help. Would I have to create a temporary table inside the trigger, create a trigger on this temporary table which then updates A_Mod, update this temporary table when the trigger is fired and then delete everything after?
Any tips greatly appreciated.
Thanks
It doesn’t appear that there is any reason in your trigger on
Bto query theBtable. You should be able to simply queryAusing the:new.a_idFrom a data modeling standpoint, however, I would be very concerned if a trigger on a child table needed to query any information from the parent table or to insert data into the same history table that the parent table writes to. That seems likely to indicate a normalization issue.