This trigger will pass on inserted values to a procedure which will insert those values in another table. I'm getting a mutating table error. How can i fix this?
CREATE OR REPLACE TRIGGER ADD_INVOICE
BEFORE INSERT OR UPDATE OF APP_NO,C_NO ON APPOINTMENT
FOR EACH ROW
DECLARE
BEGIN
POP_INVOICE(:NEW.APP_NO,:NEW.C_NO,:NEW.APP_DATE);
END;
/
CREATE OR REPLACE PROCEDURE POP_INVOICE(
I_APP_NO IN INVOICE.APP_NO%TYPE,
I_C_NO IN INVOICE.C_NO%TYPE,
I_INV_DATE IN INVOICE.INV_DATE%TYPE)
AS
CURSOR C_POP IS SELECT PRICE FROM TREATMENT T,APPOINTMENT A
WHERE T.TRT_NO=A.TRT_NO
AND A.APP_NO=I_APP_NO;
V_BILL INVOICE.BILL%TYPE;
BEGIN
OPEN C_POP;
FETCH C_POP INTO V_BILL;
UPDATE INVOICE
SET INV_NO=INV_IDSEQ.NEXTVAL,
APP_NO=I_APP_NO,
C_NO=I_C_NO,
BILL=V_BILL,
INV_DATE=I_INV_DATE;
END;
/
If a trigger does result in a mutating table error, the only real option is to rewrite the trigger as a statement-level trigger. Mutating table errors only impact row level triggers. But to use a statement level trigger, some data may need to be preserved from each row, to be used by the statement level trigger.
When something mutates, it is changing. Something that is changing is hard to analyze and to quantify. A mutating table error (ORA-04091) occurs when a row-level trigger tries to examine or change a table that is already undergoing change (via an INSERT, UPDATE, or DELETE statement).
Create Statement Level Trigger instead of Row Level Trigger. Row Level Triggers can't read Mutating tables- Change Row Level Trigger to Statement Level Trigger. IF we omit the 'For Each Row' clause from above Trigger, it will become statement level Trigger.
if the trigger attempts to select or modify the table while the trigger has not completed (ie. table is in transition). then mutating trigger error occurs. because the table is in middle of a transaction so it causes the trigger to mutate. you can change the trigger to statement level and apply the logic there.
The problem is caused by referencing the table with the trigger on it within the trigger itself. Changing the procedure to accept the TRT_NO as a parameter removes the need to include APPOINTMENT in the query, and so will avoid the mutating table exception. Depending on how many records there are for each treatment, you could even incorporate the cursor into your UPDATE statement.
I think this should do it, although I haven't been able to check against a database.
CREATE OR REPLACE TRIGGER ADD_INVOICE
BEFORE INSERT OR UPDATE OF APP_NO,C_NO ON APPOINTMENT
FOR EACH ROW
DECLARE
BEGIN
POP_INVOICE(:NEW.APP_NO,:NEW.C_NO,:NEW.APP_DATE,:NEW.TRT_NO);
END;
/
The revised procedure:
CREATE OR REPLACE PROCEDURE POP_INVOICE(
I_APP_NO IN INVOICE.APP_NO%TYPE,
I_C_NO IN INVOICE.C_NO%TYPE,
I_INV_DATE IN INVOICE.INV_DATE%TYPE,
I_TRT_NO IN APPOINTMENT.TRT_NO%TYPE
)
AS
CURSOR C_POP IS SELECT PRICE
FROM TREATMENT T
WHERE T.TRT_NO = I_TRT_NO;
V_BILL INVOICE.BILL%TYPE;
BEGIN
OPEN C_POP;
FETCH C_POP INTO V_BILL;
CLOSE C_POP;
INSERT INVOICE
(inv_no, app_no, c_no, bill, inv_date)
VALUES
(INV_IDSEQ.NEXTVAL, I_APP_NO, I_C_NO, V_BILL, I_INV_DATE);
END;
/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With