I wrote a DB trigger to monitor an insert action. After inserting a new record, I would like to automatically set the CREATION_DATE to sysdate.
I get an error when I want to insert a new record:
error
ORA-04091: table REPORT is mutating, trigger/function may not
see it
ORA-06512: at "CREATION_DATE_TEST", line 2
ORA-04088: error during execution of trigger 'CREATION_DATE_TEST'
My code:
CREATE OR REPLACE TRIGGER creation_date_test
AFTER INSERT ON REPORT FOR EACH ROW
BEGIN
UPDATE REPORT set CREATION_DATE = sysdate
WHERE ROWID = :new.ROWID;
END;
I also tried to replace ROWID = :new.ROWID with PROJECT_ID = new.PROJECT_ID. It throws the same error.
It sounds like you just want a before insert trigger that sets the :new.creation_date
create or replace trigger creation_date_test
before insert on report
for each row
begin
:new.creation_date := sysdate;
end;
Related
I'm trying to get my trigger to update a view that joins two table one of which is the table that activates the trigger causing this error
INSERT INTO MC_CLUB_MBR_TRANSACTION
*
ERROR at line 1:
ORA-04091: table ESP8339.MC_CLUB_MBR_TRANSACTION is mutating, trigger/function may not see it
ORA-06512: at "ESP8339.TRG_MC_UPD_DUES", line 2
ORA-04088: error during execution of trigger 'ESP8339.TRG_MC_UPD_DUES'
Here is the code I'm using
CREATE OR REPLACE TRIGGER TRG_MC_UPD_DUES
AFTER UPDATE OR INSERT ON
MC_CLUB_MBR_TRANSACTION
FOR EACH ROW
BEGIN
UPDATE MC_TRAN_V
SET MC_TRAN_V.DUES_DUE = (MC_TRAN_V.ANNUAL_DUES -
MC_TRAN_V.DUES_PAID_TO_DATE);
END;
/
INSERT INTO MC_CLUB_MBR_TRANSACTION
(
CLUB_CODE,
STUDENT_ID,
DUES_PAID_TO_DATE
)
VALUES
(
777,
20010,
300
);
I am trying to execute my trigger:
CREATE OR REPLACE TRIGGER Trg_video_bfr_delete
AFTER DELETE ON CMS_VIDEO
FOR EACH ROW
DECLARE
CODE varchar2(60);
BEGIN
SELECT CODE INTO CODE
from CMS_VIDEO
WHERE CODE = :OLD.CODE;
IF CODE IS NOT NULL THEN
INSERT INTO ASSET_DELETE_INDEX(CODE,ASSET_TYPE,IW_VPATH,LANGUAGE,MODIFIED_DTE)
VALUES (CODE,'Video',:old.IW_VPATH,:old.CONTENT_LANGUAGE,sysdate);
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO ASSET_DELETE_INDEX (CODE,ASSET_TYPE,IW_VPATH,LANGUAGE,MODIFIED_DTE)
VALUES (CODE,'Video',null,:old.CONTENT_LANGUAGE,sysdate);
COMMIT;
END Trg_video_bfr_delete;
/
But I am getting the following error while executing a delete command on the table
Error report -
SQL Error: ORA-04091: table LSDS.CMS_VIDEO is mutating, trigger/function may not see it
ORA-06512: at "LSDS.TRG_VIDEO_BFR_DELETE", line 6
ORA-04088: error during execution of trigger 'LSDS.TRG_VIDEO_BFR_DELETE'
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.
Could anyone please help?
You have written trigger AFTER DELETE ON CMS_VIDEO. This trigger will fire when DELETE is performed from CMS_VIDEO table. So when CMS_VIDEO table is being modified, you cannot modify or query the same table in any of your triggers, procedures or functions.
CREATE OR REPLACE TRIGGER Trg_video_bfr_delete
AFTER DELETE ON CMS_VIDEO
FOR EACH ROW
BEGIN
IF :old.CODE IS NOT NULL THEN
INSERT INTO ASSET_DELETE_INDEX(CODE, ASSET_TYPE, IW_VPATH, LANGUAGE, MODIFIED_DTE)
VALUES (:old.CODE, 'Video', :old.IW_VPATH, :old.CONTENT_LANGUAGE, sysdate);
END IF;
END Trg_video_bfr_delete;
/
This is because you are deleting record from table and same table is used as reference inside trigger. This is case of "Mutating Error". You should switch to statement level trigger is it fits your requirement or you can use compound trigger which has multiple entry point and are capable of handling such scenarios.
Please refer https://oracle-base.com/articles/9i/mutating-table-exceptions
As per the snippet provided, I dont see any point in doing a SELECT on mutating TABLE.
We can easily ise :OLD.CODE to fetch the value. Hope below snippet helps.
CREATE OR REPLACE TRIGGER Trg_video_bfr_delete AFTER
DELETE ON CMS_VIDEO FOR EACH ROW
-- DECLARE CODE VARCHAR2(60);
BEGIN
-- SELECT CODE INTO CODE FROM CMS_VIDEO WHERE CODE = :OLD.CODE;
IF CODE IS NOT NULL THEN
INSERT
INTO ASSET_DELETE_INDEX
(
CODE,
ASSET_TYPE,
IW_VPATH,
LANGUAGE,
MODIFIED_DTE
)
VALUES
(
:old.code,
'Video',
:old.IW_VPATH,
:old.CONTENT_LANGUAGE,
sysdate
);
END IF;
EXCEPTION
WHEN OTHERS THEN
INSERT
INTO ASSET_DELETE_INDEX
(
CODE,
ASSET_TYPE,
IW_VPATH,
LANGUAGE,
MODIFIED_DTE
)
VALUES
(
:old.code,
'Video',
NULL,
:old.CONTENT_LANGUAGE,
sysdate
);
COMMIT;
END Trg_video_bfr_delete;
I got an example that better explains the situation. I have a table A
CREATE TABLE A( ID NUMBER, VAL NVARCHAR2(255) )
and I create a trigger that does an update on the row it's just inserted
CREATE OR REPLACE TRIGGER XXX
AFTER INSERT
ON A
FOR EACH ROW
DECLARE
BEGIN
UPDATE A SET VAL = 'LOL' WHERE ID = :NEW.ID;
END;
When I perform an insert
INSERT INTO A VALUES(1, 'XX')
I get
ORA-04091: table name is mutating, trigger/function may not see it
Is there a workaround?
You don't need an update, just assign the new value in a BEFORE trigger.
CREATE OR REPLACE TRIGGER XXX
BEFORE INSERT --<< You need a BEFORE trigger for this to work.
ON A
FOR EACH ROW
BEGIN
:new.val := 'LOL';
END;
I created a trigger to insert a log in a table when an insert is made on another table.
This is the code of the trigger:
CREATE OR REPLACE TRIGGER scheme1.Inserting_Feed
AFTER INSERT ON scheme2.payments FOR EACH ROW
BEGIN
INSERT INTO scheme2.db-logger(ID, TECHNOLOGY, WORKFLOW, NAME_EVENT, TIME_EVENT)
VALUES(:NEW.id,'Repository','UP',(select repo.name
from scheme1.repository repo
join scheme2.payments pay
on repo.id = pay.repository_id
where repo.id = NEW.repository_id), SYSDATE);
END;
I try to run this trigger but when I make an insert on the table payments I get following error:
Error MT101-GENERAL_LOAD_ERROR: java.sql.SQLSyntaxErrorException:
ORA-04091: table scheme1.payments is mutating, trigger/function may
not see it ORA-06512: at "scheme1.Inserting_Feed", line 2 ORA-04088:
error during execution of trigger 'scheme1.Inserting_Feed'
What I understand is that the error says the table is changing, but the trigger doesn't see it. How does this come?
Why join to the scheme2.payments table in the subquery in the insert statement? Couldn't you just do:
CREATE OR REPLACE TRIGGER scheme1.inserting_feed
AFTER INSERT
ON scheme2.payments
FOR EACH ROW
BEGIN
INSERT INTO scheme2.db_logger (id,
technology,
workflow,
name_event,
time_event)
VALUES ( :new.id,
'Repository',
'UP',
(SELECT repo.name
FROM scheme1.repository repo
WHERE repo.id = :new.repository_id),
SYSDATE);
END;
/
Hope someone can help with this. I am new to triggers and I am trying to create a trigger that checks to see if the record being modified has a specific value.
example
I have a table called Filing that has a filing_id and a filing_status, I want to prevent someone from updating or deleting any records in that table has a filing_status="FILED".
so if i have the following
Filing_id Filing_status Val
--------- ------------- ---
0 Filed X
If someone tried to modify Val the trigger should stop it
I have created the following trigger:
CREATE or replace TRIGGER TRG_PREV_FILING
BEFORE DELETE or UPDATE
ON PF.FILING
FOR EACH ROW
declare
rowcnt number;
BEGIN
SELECT COUNT(filing_id) INTO rowcnt FROM PF.FILING
where status = 'FILED'
and filing_id = :new.filing_id;
if (rowcnt > 0)
then
raise_application_error (-20100, 'You can not delete Or Update initial record');
end if;
END;
The problem I am facing is I am getting:ORA-04091 which is "Table Filing is mutating, Trigger/function may not see it"
So basically I can't query on the same table that I am executing the trigger on? Is that the problem in my case and does anyone know a work around this?
I appreciate any help
You do not have to query the table trigger is firing on to be able to do that kind of check. You can get value of a column that is being modified using :old. Here is an example:
SQL> create table filing(
2 status varchar2(31),
3 val number
4 );
Table created
SQL> create or replace trigger TRG_FILING before delete or update on FILING
2 for each row
3 begin
4 if lower(:old.status) = 'filed'
5 then
6 raise_application_error(-20000, 'You cannot delete or modify this record');
7 end if;
8 end;
SQL> /
Trigger created
SQL> insert into FILING values('FILED', null);
1 row inserted
SQL> insert into filing values('OK', 1);
1 row inserted
SQL> commit;
Commit complete
SQL> select *
2 from filing;
STATUS VAL
------------------------------- ----------
FILED
OK 1
SQL> delete
2 from filing
3 where val is null;
ORA-20000: You cannot delete or modify this record
ORA-06512: at "HR.TRG_FILING", line 4
ORA-04088: error during execution of trigger 'HR.TRG_FILING'
The basic point is that you should design you database in a way that the trigger does its validation based on the updated/deleted row. If you have several rows with the same filing_id then you can overwork you database design. Maybe you really only check against the own table in which case you can use :old. But when you have several rows to check (which I assume because you make a count) then you have to use two tables. Here is a suggestion.
create table filing_status (filing_id number, status varchar2(10));
create table filing_content (filing_id number, content_id number, content varchar2(200));
CREATE or replace TRIGGER TRG_PREV_FILING
BEFORE DELETE or UPDATE
ON FILING_content
FOR EACH ROW
declare
rowcnt number;
BEGIN
SELECT COUNT(filing_id) INTO rowcnt FROM FILING_status
where status = 'FILED'
and filing_id = :new.filing_id;
if (rowcnt > 0)
then
raise_application_error (-20100, 'You can not delete Or update filed record');
end if;
END;
/
insert into filing_status values (1, 'FILING');
insert into filing_content values (1, 1, 'foo');
insert into filing_content values (1, 2, 'bar');
insert into filing_status values (1, 'FILED');
update filing_content set content = 'bahr' where filing_id = 1 and content_id = 2;
ERROR at line 1:
ORA-20100: You can not delete Or update filed record
ORA-06512: at "DEMO.TRG_PREV_FILING", line 9
ORA-04088: error during execution of trigger 'DEMO.TRG_PREV_FILING'