I have a problem with a "after insert" trigger which won't pass the value to a stored procedure that i'm calling inside the trigger.
It works ok for update and also i should mention that i am querying the table in the procedure that i am calling.
It goes something like:
create or replace trigger test_trg
after insert or update on table1
for each row
begin
test_procedure(:new.value1);
end;
The procedure looks inside table1 and inserts in table2 hints about what should be added in table1 based on the current inserted/updated row.
Thanks in advance!!
I found it!
The problem was not the trigger, it was in the procedure. I was performing a "dirty read" based on the record ID that i was sending (the record id of a new row).
Even though my trigger is "after insert" it looks like my row can't be found by the procedure and i was basing all my operations on it.
Fixed it by adding more parameters to the procedure and passing :new values straight from the trigger for everything i needed.
A trigger transaction is depend on its statement transaction. Therefore you can not read uncommitted records. So you should transfer "test_procedure" codes into your trigger and use :New record values to insert data into table2.
Your code should look like this:
create or replace trigger test_trg
after insert or update on table1
for each row
begin
if inserting then
insert into table2(ID, F1, F2, ...)
values (NEW_ID_VALUE, :NEW.F1_VALUE, :NEW.F2_VALUE, ...);
elsif updating then
update table2
set F1 = :NEW.F1_VALUE
, F2 = :NEW.F2_VALUE
where TABLE1_ID_FK = :NEW.ID;
end if;
end;
Related
My Oracle DB has a table DOC_WF_COMM and its primary key is DWFC_ID. Primary key value is based on a sequence called SQ_DOC_WF_COMM.
I have created a row level AFTER INSERT trigger on that table and inside the trigger I need to join the inserted record with some other tables like this:
create or replace TRIGGER TRG_DOC_WF_COMM_AFT_INS AFTER INSERT ON DOC_WF_COMM REFERENCING OLD AS OLD NEW AS NEW FOR EACH ROW
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
L_SUBJECT VARCHAR2(300);
L_BODY CLOB;
L_PNT_CODE VARCHAR(100) := NULL;
L_DR_PRJ_ID NUMBER(12);
L_STR_EMAIL VARCHAR2(120);
L_DWFC_TO_USR_ID VARCHAR2(12);
L_PNT_ID NUMBER(12);
L_PNT_EMAIL_YN VARCHAR(1);
L_PNT_ACTIVE_YN VARCHAR(1);
L_PNT_NOTIFY_YN VARCHAR(1);
BEGIN
IF INSERTING THEN
L_PNT_CODE := 'WFNT_MESSAGE';
SELECT DR_PRJ_ID, STR_EMAIL, DWFC_TO_USR_ID INTO L_DR_PRJ_ID, L_STR_EMAIL, L_DWFC_TO_USR_ID
FROM DOC_WF_COMM
JOIN DOC_WF_USERS ON DWFU_ID = DWFC_DWFU_ID
JOIN DOC_WORKFLOW ON DWF_ID = DWFU_DWF_ID
JOIN DOCUMENT_REF ON DR_ID = DWF_DR_ID
JOIN ST_REGISTER ON STR_ID = DWFU_STR_ID
WHERE DWFC_ID = :NEW.DWFC_ID AND DWFC_RESPONSE IS NULL;
-- SOME QUERIES HERE
END IF;
END;
The trigger is compiled successfully and when I insert record into DOC_WF_COMM table I get this error:
ORA-01403: no data found ORA-06512
The error is :NEW.DWFC_ID in WHERE clause and I have change it to these values:
:OLD.DWFC_ID
SQ_DOC_WF_COMM.NEXTVAL
SQ_DOC_WF_COMM.CURRVAL
But no any luck. Any idea why this error is and how can I resolve it?
The problem is this line in your trigger:
PRAGMA AUTONOMOUS_TRANSACTION;
That means the trigger executes as an isolated transaction in a separate session, which means it cannot see the uncommitted state of any other session. Crucially this includes the session which fires the trigger, so the autonomous transaction cannot see the record you just inserted. Hence, NO_DATA_FOUND.
You haven't posted the whole trigger or explained what you're trying to do, so only you know why you have included the PRAGMA. However, the chances are you don't need it. Remove the PRAGMA (and the COMMIT) and your trigger should work just fine.
If I understood you correctly, create a local variable and put the next sequence value in there. Then it can be referenced throughout the code, always having the same value. Something like this:
declare
l_seq number := my_seq.nextval;
begin
insert into table_a (id, ...) values (l_seq, ...);
update table_b set id = l_seq where ...
select ... into ... from ... where id = l_seq;
end;
I changed the query inside the trigger to this, it is working fine
SELECT STR_PRJ_ID, STR_EMAIL, :NEW.DWFC_TO_USR_ID INTO L_DR_PRJ_ID, L_STR_EMAIL, L_DWFC_TO_USR_ID
FROM DOC_WF_USERS, ST_REGISTER
WHERE :NEW.DWFC_TO_USR_ID = DWFU_US_ID AND DWFU_STR_ID = STR_ID AND DWFU_ID = :NEW.DWFC_DWFU_ID;
Not sure why is that. If anyone can figure out the mistake in the query given in the question, please let me know. Thanks
So I am trying to add age with price and store the result on another table with the ID of the person who did this. I am able to set the business rule by making the trigger but when I check my second (END) table, there is nothing there.. Here is my code for the trigger:
CREATE OR REPLACE TRIGGER JIM
BEFORE INSERT ON END
FOR EACH ROW ENABLE
DECLARE
V_AGE JIM.AGE%TYPE;
V_PRICE JIM.PRICE%TYPE;
v_prices NUMBER(20);
BEGIN
SELECT AGE,PRICE INTO V_AGE,V_PRICE FROM JIM WHERE ID=:NEW.ID;
v_prices:=V_AGE+V_PRICE;
INSERT INTO END VALUES(:new.ID,v_prices);
END;
However, When I insert values onto the JIM table using the following code:
insert into jim values(4,'Sim',45,100);
nothing actually gets stored on the END table. i am sort of new to triggers and its so confusing. Please let me know what to do. thanls
Don't use a keyword end as a table name, this causes problem during
creation of trigger. I've presumed the table's name as t_end.
I think you are confused on which table to define trigger. It seems
you should define on table jim instead of t_end.
I've presumed you have a sequence named seq_end to populate the id
column of the table t_end
So , your trigger creation statement will be as follows :
create or replace trigger trg_ins_jim before insert on jim for each row
declare
v_id_end t_end.id%type;
v_prices t_end.prices%type;
begin
v_prices := :new.age + :new.price;
v_id_end := seq_end.nextval; insert into t_end values(v_id_end, v_prices);
/* if you have defined sequence for t_end as default value of id column, you may change the upper row as "insert into t_end(prices) values(v_prices);" and there would be no need for "v_id_end" */
end;
and when you issue insert into jim values(4,'Sim',45,100); command, you'll also have values inserted into t_end.
If there is only one table, then the SELECT and the INSERT are redundant.
CREATE OR REPLACE TRIGGER trigger_name
BEFORE INSERT ON table_name
FOR EACH ROW
BEGIN
:NEW.PRICES := :NEW.AGE + :NEW.PRICE;
END;
Possible duplicate
I have a trigger that gets a sequence number to put into my id column when insert a Row, the question is, how easily retun the new inserted row as resultSet.
create or replace trigger trg_Dependencia_id
before insert on DEPENDENCIA
for each row
begin
select DEPENDENCIA_id_seq.nextval
into :new.id
from dual;
end;
In Oracle, Triggers does not return any value. Also, triggers are not for this issues.
Maybe, you can insert your nextval a temp table after insert your table(DEPENDENCIA.DEPENDENCIA_id). Then you can handle it with a function.
Is it possible to reference a second table within a trigger?
create or replace trigger table1
before update of status_code on table1
for each row
declare z_user_id table2.user_id;
begin
if :new.status_code in (30,40) then
:new.z_open_01 := nvl(:OLD.z_user_id, nvl(:NEW.z_user_id, :old.z_open_01));
end if;
end;
/
As to your question: Yes.
The :old and :new constructs only apply to the table that cause the trigger to fire.
The way you have that written you are triggering off of Table1, but your description sounds like you want to grab a value from table one when something in Table2 changes.
But you didn't say what you want to DO with the userid you grab.
If you create a trigger on Table2, read a value from Table1, and save the value in a column in the row that fired the trigger you are gtg. Other scenarios get more complex.
so, based on comments something like:
create or replace trigger table2
after update of status_code on table2
for each row when (:new.status_code in (30,40))
declare t1_user Table1.user_id%type;
begin
Select user_id into t1_user from Table1 where <condition>
:new.z_open_01 := t1_user;
end if;
end;
/
setting up whatever condition select the desired user from Table1.
Am very new to Oracle triggers. Suppose I have a trigger on an insert in the table emp. Is there a way to find out what was the inserted record that fired the trigger. I wanted the trigger to have code that does something if the inserted record was a particular value.
Assuming you have a row-level trigger, you can simply use the :NEW pseudo-record
CREATE TRIGGER name_of_trigger
BEFORE INSERT ON emp
FOR EACH ROW
DECLARE
<<declare variables>>
BEGIN
IF( :new.ename = 'JUSTIN' )
THEN
<<do something if the newly inserted ENAME value is 'JUSTIN'>>
END IF;
END;
For a DDL trigger, the approach is completely different. In that case, the pseudofunctions ora_dict_obj_owner and ora_dict_obj_name will return the owner and name of the table that the DDL statement is operating on.
The row that is being insertes is available as NEW in the trigger
Check out the manual for more details.
http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/create_trigger.htm#BABEBAAB
http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS99955