Home > OS >  Function/Trigger Mutating
Function/Trigger Mutating

Time:01-24

Is there any way to write after update trigger on the same table for the below problem

Problem statement: whenever the user updates selection column from yes to no with items as 'TV' and id as 1 then selection for the same id and items as 'remote' record should be updated with selection as 'No'

Trigger:

Create trigger ttt 
After update on home_items
For each row
Begin
If (new.items = 'TV' AND new.selection = 'No') Then
Update home_items h set h.selection = 'No' where new.id = h.id and h.items = 'Remote';
End If;
End;

Error: ORA-04091: table home_items is mutating, trigger/f0unction may not see it

CodePudding user response:

Use a compound trigger:

CREATE TRIGGER remove_tv_and_remote 
FOR UPDATE ON home_items
COMPOUND TRIGGER
  TYPE ids_type IS TABLE OF HOME_ITEMS.ID%TYPE;
  ids ids_type := ids_type();
AFTER EACH ROW
  IS
  BEGIN
    IF     :new.items     = 'TV'
       AND :new.selection = 'No'
       AND :old.selection = 'Yes'
    THEN
      ids.EXTEND(1);
      ids(ids.COUNT) := :new.id;
    END IF;
  END AFTER EACH ROW;
AFTER STATEMENT
  IS
  BEGIN
    FORALL i IN 1 .. ids.count
      UPDATE home_items
      SET   selection = 'No'
      WHERE id        = ids(i)
      AND   selection = 'Yes'
      AND   items     = 'Remote';
  END AFTER STATEMENT;
END;
/

If you have the table:

CREATE TABLE home_items (id, items, selection) AS
SELECT 1, 'TV',     'Yes' FROM DUAL UNION ALL
SELECT 1, 'Remote', 'Yes' FROM DUAL;

And then do:

UPDATE home_items
SET   selection = 'No'
WHERE items     = 'TV';

Then:

SELECT * FROM home_items;

Outputs:

ID ITEMS SELECTION
1 TV No
1 Remote No

db<>fiddle here

CodePudding user response:

This infamous ORA-04091: table ... is mutating means, Oracle is telling you: "I cannot guarantee, that what you want is deterministic".

Imagine that you run an update on a table home_items, this update would modify 2 rows in random order (the order of updates cannot be predicted).

After update of 1st row you execute a trigger, which will see 2nd row and not-modified. And now imagine that due to change of exec plan the order of rows updated is opposite.

There are various ways how to overcome this "problem", many articles were written about this topic. But the root of the problem is determinism of PL/SQL code, Oracle is not smart enough to deduce whether your code is deterministic or not.

PS: in your case you might need just change your trigger into before update.

  •  Tags:  
  • Related