Oracle Trigger inserting row into custom table - oracle

I have a Post-Insert Oracle trigger that is simply going to be used to insert a row into a table when the triggered table has a record added to it. My code is a simple insert:
BEGIN
INSERT INTO R5CHECKLISTMAP(CLM_CHKLINECODE, CLM_SYSTEMCODE)
VALUES(10, 'TEST');
END;
However, I get the error:
ORA 01006 - Bind Variable does not exist POST-INSERT 10 Before Binding
I know this has to be something simple, but I cannot figure out what the problem could be.

Related

oracle : Trigger not inserting records into table

I have a trigger but it's not inserting the records into target table.
create or replace trigger ins_det_trig1
after insert on Table_a
declare
pragma autonomous_transaction;
---
begin
insert into inf_det
select
a.loc_id,
a.genre_id,
to_char(a.emp_date,'yyyy-mm-dd'),
a.san_seq
from Table_b a ,
Table_a b
where
b.emp_date=a.emp_date
and b.genre_id=a.genre_id
and b.san_seq=a.san_seq;
commit;
exception
when others
Rollback;
end;
pls help me on this
First of all the trigger is invalid, so it won't do anything. You are using a variable named v_err that you don't declare.
Then, you are swallowing all exceptions. If something goes wrong, you fill that variable with the error code and then silently end the trigger. Thus you'll never get informed when the trigger fails.
But the main problem is that you are not using the trigger as you should use triggers in Oracle. The trigger is an after row trigger (AFTER INSERT ... FOR EACH ROW) and hence fires once per row on inserts of table_a rows. The values that got inserted in a new row can be accessed with :new, e.g. :new.business_date.
You, however, ignore these values and select from the table instead. But at the moment of your select the table is mutating. Let's say we write an insert statement that inserts two rows. The trigger fires two times. It is left to chance which row gets inserted first. Oracle sees this and when you are inside the trigger and try to select, it tells us that the content of the table is not deterministic, as the other row may already be in the table or not. We get a mutating table exception.
Having said this: It seems you want an after statement trigger. A trigger that fires after the insert of the rows is complete. For this to happen remove the FOR EACH ROW clause and the related REFERENCING clause, too.
create or replace trigger ins_det_trig1
after insert on Table_a
declare
...
begin
...
end;

Cx_oracle trigger error

I am trying to create a simple trigger in cx_oracle which copies values in a table called Student when some value is inserted in the table studentTemp. There are only two columns in each table namely stud_ID and stud_Name. When I try to insert value in StudentTemp by using
cur.execute("INSERT INTO studentTemp VALUES(1, 'Bob')")
I am getting error DatabaseError: ORA-04098: trigger 'S12345.INSERT_STUD' is invalid and failed re-validation. Following is the code
cur.execute('''CREATE OR REPLACE TRIGGER insert_Stud
AFTER INSERT ON studentTemp
FOR EACH ROW
BEGIN
INSERT INTO Student(Stud_ID,Stud_Name) VALUES
(:new.Stud_ID, :new.Stud_Name);
END;''')
I have also tried
cur.execute('''CREATE OR REPLACE TRIGGER insert_Stud
AFTER INSERT ON studentTemp
REFERENCING NEW AS new
FOR EACH ROW
BEGIN
INSERT INTO Student(Stud_ID,Stud_Name) VALUES (:new.Stud_ID, :new.Stud_Name);
END;/''')
But still get the same error
I can get it work if I use a stored procedure like this
# create insertStudent() stored procedure
cur.execute('''CREATE OR REPLACE PROCEDURE insertStudent(
sID IN STUDENT.STUDENT_ID%TYPE,
sName IN STUDENT.STUDENT_NAME%TYPE)
IS
BEGIN
INSERT INTO STUDENT VALUES(sID, sName);
END;''')
# create insert_Stud() trigger
cur.execute('''CREATE OR REPLACE TRIGGER insert_Stud
AFTER INSERT ON studentTemp
FOR EACH ROW
BEGIN
insertStudent(:new.Stud_ID, :new.Stud_Name);
END;''')
Can someone kindly tell me how to fix this. Thanks
It seems to me like you have an error in naming your Student-Table Fields.
In your Procedure, the colums are referenced as
STUDENT.STUDENT_ID
STUDENT.STUDENT_NAME
In your trigger, you call them
INSERT INTO Student(**Stud_ID**,**Stud_Name**) VALUES ...
Try using SQL*Plus to create the trigger. Then use the "show errors" command to see what the problem is. After that you should be able to use cx_Oracle without any difficulty. The only difference is that the trailing / in SQL*Plus does not need to be there.

Oracle_Trigger: Auto Update Of a Column Based Upon INSERT/UPDATE

This might appear a simple query for most of you, but I am a beginner in Oracle DB.
A table has been created with below script-
CREATE TABLE PLAN_TABLE
(
PL_ID DECIMAL(10,0) PRIMARY KEY NOT NULL
,PL_NAME VARCHAR2(300) DEFAULT NULL
,UPDATED_TS TIMESTAMP DEFAULT SYSDATE NOT NULL
,DELETE_FLAG DECIMAL(10,0) DEFAULT 0 NOT NULL
);
The requirement is to have SYSDATE for UPDATED_TS for any new record inserted into the table and also in case when the DELETE_FLAG is updated to 1. Can it be done by trigger?
The below trigger was created-
CREATE OR REPLACE TRIGGER PT_BEFORE_INSERT_TR
BEFORE INSERT ON PLAN_TABLE
FOR EACH ROW
BEGIN
SELECT SYSDATE INTO :new.UPDATED_TS FROM DUAL;
dbms_output.put_line('Inserted');
END;
/
Below error was encountered while inserting record into the table-
error: ORA-04091: table I60_SCH04.PLAN_TABLE is mutating, trigger/function may not see it
Can you please help in letting me know that where am I committing the mistake? Is there any better way to achieve the requirement based upon INSERT/UPDATE?
The actual error you get is due to the fact that you try to select from a table that you actually are changing. To prevent the issue there are a couple of methods, but in you case things are really simple.
SYSDATE is a function, that you could call directly inside PL/SQL block (which a trigger actually is) and use the value returned to update the set the column value
CREATE OR REPLACE TRIGGER PT_BEFORE_INSERT_TR
BEFORE INSERT ON PLAN_TABLE
FOR EACH ROW
BEGIN
:new.UPDATED_TS := sysdate;
dbms_output.put_line('Inserted');
END;
/
OK, this covers the insert part.
For updating - once again, many options. One could be - change your trigger to BEFORE INSERT OR UPDATE ON PLAN_TABLE.
In this case whenever you issue update or insert - this trigger is fired for each row and updates the date column accordingly.
And of course you could use particular checks available in triggers, something like
IF INSERTING OR UPDATING('DELETE_FLAG') THEN
...
END IF;
and code in the logic you need.

Before-insert trigger gets 'too many rows' error

I have a trigger:
create or replace trigger trig
before insert on sistem
for each row
declare
v_orta number;
begin
SELECT v_orta INTO :new.orta_qiymet
FROM sistem;
v_orta:=(:new.riyaziyyat+:new.fizika)/2;
insert into sistem(orta_qiymet)
values(v_orta);
end trig;
When I insert a row:
insert into sistem(riyaziyyat,fizika) values(4,4)
I get an error:
Why am I getting that error?
This is fundamentally not understanding how triggers work. You can't generally select from the table the trigger is against, and a before-insert trigger shouldn't not insert into the same table again - as that would just cause the trigger to fire again, infinitely (until Oracle notices and stops it). You aren't even currently using the v_orta value you're attempting to query.
I suspect you think the trigger is instead of your original insert perhaps, and really you want to set the orta_qiymet value in the newly-inserted row automatically based on the other two columns you have supplied. To do that you don't (and can't) select those values; instead you refer to the :NEW pseudorecord as you are already doing, and then set the third column value in that same pseudorow:
create or replace trigger trig
before insert on sistem
for each row
begin
:new.orta_qiymet := (:new.riyaziyyat + :new.fizika)/2;
end trig;
/
There is a lot of information in the documentation; this is similar to one of the examples.

Mutating error on after insert trigger

The below code is giving a mutating error.
Can any1 pls help in solving this.
CREATE OR REPLACE TRIGGER aso_quote_cuhk_trigger
BEFORE INSERT
ON aso.aso_quote_headers_all
FOR EACH ROW
BEGIN
UPDATE aso.aso_quote_headers_all
SET quote_expiration_date=sysdate+90
where quote_header_id=:new.quote_header_id;
END;
/
In oracle there are two levels of triggers: row level and table level.
Row level triggers are executed for each row. Table level triggers executed per statement, even if a statement changed more then one row.
In a row level trigger, you cannot select/update the table itself that has the trigger: you will get a mutating error.
In this case, there is no need for an UPDATE statement. Just try this:
CREATE OR REPLACE TRIGGER aso_quote_cuhk_trigger
BEFORE INSERT
ON aso.aso_quote_headers_all
FOR EACH ROW
BEGIN
:new.quote_expiration_date=sysdate+90;
END;
/
EDIT Rajesh mentioned it is possible, that before inserting a new row, OP wants to update all other records in the aso_quote_headers_all table.
Well, this is feasible, but it's a little tricky. To do this properly, you will need
A pl/sql package and a variable in the package header that is modified by the triggers. This variable could be a list holding the IDs of newly inserted records. Row level after insert trigger would add a new ID to the list. The content of this package variable will be different for each different session, so let's call this variable session_variable.
Row level after insert trigger, that would add new ID to the session_variable.
Table level after insert trigger that would get IDs from the session_variable, process the ID and then remove it from the session_variable. This trigger could execute necessary selects/updates on the aso_quote_headers_all. After a newly inserted ID is processed, this trigger should make sure it gets removed from the session_variable.
I realise you must have resolved your issue by now. However I am adding this answer below to help anyone else facing similar problem as you and I faced.
I recently encountered mutating table (ORA-04091: table XXXX is mutating, trigger/function may not see it) issue and after searching around realised the Compound Triggers feature available in 11g. If you're on 11g following compound trigger would have solved your issue.
CREATE OR REPLACE TRIGGER aso_quote_cuhk_trigger
FOR INSERT ON aso.aso_quote_headers_all
COMPOUND TRIGGER
row_id rowid;
AFTER EACH ROW IS
BEGIN
row_id := :new.rowid;
END AFTER EACH ROW;
AFTER STATEMENT IS
BEGIN
UPDATE aso.aso_quote_headers_all
SET quote_expiration_date = sysdate+90
WHERE rowid = row_id;
END AFTER STATEMENT;
END aso_quote_cuhk_trigger;
/
A word about how it works. This compound trigger fires 2 events :
First is AFTER EACH ROW where we capture the rowid of newly inserted row
Next is AFTER STATEMENT where we update the table using rowid (captured during first event) in the WHERE clause.
A useful link if you want to read more about Compound Triggers.

Resources