Home » SQL & PL/SQL » SQL & PL/SQL » Triggers/mutating
Triggers/mutating [message #10998] Sun, 29 February 2004 12:59 Go to next message
Carl Hanson
Messages: 4
Registered: January 2004
Junior Member
So I've made this trigger that will subtract the transaction total from the members balance, or delete the transaction if they don't have enough to complete the transaction. Problem is, I get the 'table is mutating, trigger/function may not see it' error when I try inserting a transaction for which the member's balance is not high enough. Any ideas on how I can change/redo the if structure to elminate this error?

Any help would be greatly appreciated..

CREATE OR REPLACE TRIGGER ReduceBalance
   AFTER INSERT ON TRANSACTION
   FOR EACH ROW
   WHEN (new.TTYPE = 'BUY')
   DECLARE b INTEGER;
   BEGIN 
      SELECT BALANCE INTO b
      FROM MEMBER m
      WHERE m.MID = :new.MID;
     
      IF b >= :new.AMOUNT THEN
         UPDATE MEMBER m
         SET BALANCE = BALANCE - :new.AMOUNT
         WHERE m.MID = :new.MID;
      ELSE
         DELETE FROM TRANSACTION WHERE MID = :new.MID AND  SYMBOL = :new.SYMBOL AND TDATE = :new.TDATE;
      END IF;
   END;
.
run
Re: Triggers/mutating [message #10999 is a reply to message #10998] Sun, 29 February 2004 14:39 Go to previous messageGo to next message
Barbara Boehmer
Messages: 9090
Registered: November 2002
Location: California, USA
Senior Member
It can't delete from tansaction because transaction is the table that the trigger is on, so it is mutating (changing). Instead of deleting, you should use raise_application_error, which will cause the insert to be rejected and an error message returned to the inserter. Please see the example below.

scott@ORA92> CREATE OR REPLACE TRIGGER ReduceBalance
  2  	AFTER INSERT ON transaction
  3  	FOR EACH ROW
  4  	WHEN (NEW.ttype = 'BUY')
  5  DECLARE
  6  	b INTEGER;
  7  BEGIN
  8  	SELECT balance
  9  	INTO   b
 10  	FROM   member m
 11  	WHERE  m.mid = :NEW.mid;
 12  
 13  	IF b >= :NEW.amount THEN
 14  	   UPDATE member m
 15  	   SET	  balance = balance - :NEW.amount
 16  	   WHERE  m.mid = :NEW.mid;
 17  	ELSE
 18  	   <b>RAISE_APPLICATION_ERROR (-20001, 'Insufficient funds!');</b>
 19  	END IF;
 20  END ReduceBalance;
 21  /

Trigger created.

scott@ORA92> SHOW ERRORS
No errors.
scott@ORA92> -- starting data:
scott@ORA92> SELECT * FROM member
  2  /

       MID    BALANCE
---------- ----------
         1       1000

scott@ORA92> SELECT * FROM transaction
  2  /

no rows selected

scott@ORA92> -- test valid insert:
scott@ORA92> INSERT INTO transaction (mid, ttype, amount) VALUES (1, 'BUY', 600)
  2  /

1 row created.

scott@ORA92> SELECT * FROM member
  2  /

       MID    BALANCE
---------- ----------
         1        400

scott@ORA92> SELECT * FROM transaction
  2  /

       MID TTY     AMOUNT
---------- --- ----------
         1 BUY        600

scott@ORA92> -- test invalid insert due to insufficient funds:
scott@ORA92> INSERT INTO transaction (mid, ttype, amount) VALUES (1, 'BUY', 700)
  2  /
INSERT INTO transaction (mid, ttype, amount) VALUES (1, 'BUY', 700)
            *
ERROR at line 1:
ORA-20001: Insufficient funds!
ORA-06512: at "SCOTT.REDUCEBALANCE", line 14
ORA-04088: error during execution of trigger 'SCOTT.REDUCEBALANCE'

scott@ORA92> SELECT * FROM member
  2  /

       MID    BALANCE
---------- ----------
         1        400

scott@ORA92> SELECT * FROM transaction
  2  /

       MID TTY     AMOUNT
---------- --- ----------
         1 BUY        600
Re: Triggers/mutating [message #11000 is a reply to message #10999] Sun, 29 February 2004 14:42 Go to previous message
Carl Hanson
Messages: 4
Registered: January 2004
Junior Member
Awesome! Thanks Barbara. Once again my database assignment is saved by this forum. :D
Previous Topic: Can plsql call an exe file written in vb?
Next Topic: Create trigger on table that updates and appends
Goto Forum:
  


Current Time: Thu Apr 25 11:49:00 CDT 2024