Before insert trigger for a sequence - oracle

I have to make a trigger that fills the primary key field user_id from a sequence.
So I did this first:
Create sequence user_seq;
Then I created the trigger. I also had to make the function that checks to see if the values in emp_id for the table users in the schema system_users exists in the table employees for the schema HRM_REPO. This part is in comments because it caused major issues.
create or replace trigger user_trig_bi
Before insert on system_users.users
for each row
begin
select user_seq.nextval
into new.user_ID
From dual;
/*where exists (SELECT emp_id
from hrm_repo.employees
where hrm_repo.employees.emp_id = system_users.users.emp_id);*/
END;
I get the error that new.user_id must be defined.
If I do run the where exists part, I get the notification that system_users.users.emp_id is an invalid identifier.
Please help me!
Regards,
Vinny

Replace new with :new:
create or replace trigger user_trig_bi
Before insert on system_users.users
for each row
begin
select user_seq.nextval
into :new.user_ID
From dual;
END;
or simply:
create or replace trigger user_trig_bi
Before insert on system_users.users
for each row
begin
:new.user_ID := user_seq.nextval;
END;

Dmitry got the answer already. As an addition: you should never try to check referential integrity using triggers, it will not work correctly. You should add foreign key (system_users.users.emp_id) references hrm_repo.employees(emp_id) instead. See http://docs.oracle.com/cd/B10500_01/server.920/a96524/c22integ.htm if you missed it before.

Related

How can I get the inserted primary key value from AFTER INSERT trigger in Oracle?

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

Oracle update trigger on the same table

I want to update field data_aktualizacji when some row in the same table is updated. I created the following compound trigger.
CREATE OR REPLACE TRIGGER oferta_update_trigger
FOR UPDATE ON oferty
compound TRIGGER
id_oferty number(10);
AFTER EACH ROW IS
BEGIN
id_oferty := :new.idk;
END AFTER EACH ROW;
AFTER STATEMENT IS
BEGIN
UPDATE oferty SET data_aktualizacji = SYSDATE WHERE idk = id_oferty;
END AFTER STATEMENT;
END;
/
When I want to update some record, I get the following error.
SQL Error: ORA-00036: maximum number of recursive SQL levels (50) exceeded.
How to solve this problem? I this that some loop is created, but I don't know, how to workaround this.
Update oracle to alter the column to default to sysdate
Alter table oferty alter column data_aktualizacji set default sysdate
No need for trigger at all
As Ctznkane525 wrote, you definitively should use default-value to perform this action.
If you don't want to use default you can modify new.data_aktualizacji:
CREATE OR REPLACE TRIGGER oferty_update_aktualizacji
BEFORE INSERT OR UPDATE
ON oferty
FOR EACH ROW
DECLARE
BEGIN
:new.data_aktualizacji:= sysdate;
END;

Addition of values in two columns isn't working in PL/SQL ORACLE

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

Create trigger to insert into another table

I have some problem executing the trigger below:
CREATE OR REPLACE TRIGGER AFTERINSERTCREATEBILL
AFTER INSERT
ON READING
FOR EACH ROW
DECLARE
varReadNo Int;
varMeterID Int;
varCustID Varchar(10);
BEGIN
SELECT SeqReadNo.CurrVal INTO varReadNo FROM DUAL;
Select MeterID INTO varMeterID
From Reading
Where ReadNo = varReadNo;
Select CustID INTO varCustID
From Address A
Join Meter M
on A.postCode = M.postCode
Where M.MeterID = varMeterID;
INSERT INTO BILL VALUES
(SEQBILLNO.NEXTVAL, SYSDATE, 'UNPAID' , 100 , varCustID , SEQREADNO.CURRVAL);
END;
Error Message:
*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.
Does it mean that I am not suppose to retrieve any details from table Reading?
I believe that the issue occur as I retrieving data from Table Reading while it is inserting the value:
SELECT SeqReadNo.CurrVal INTO varReadNo FROM DUAL;
Select MeterID INTO varMeterID
From Reading
Where ReadNo = varReadNo;
It's there anyway to resolve this? Or is there a better method to do this? I need to insert a new row into table BILL after entering the table Reading where the ReadNo need to reference to the ReadNo I just insert.
You cannot retrieve records from the same table in a row trigger. You can access values from actual record using :new and :old (is this your case?). The trigger could then be rewritten to
CREATE OR REPLACE TRIGGER AFTERINSERTCREATEBILL
AFTER INSERT
ON READING
FOR EACH ROW
DECLARE
varCustID Varchar(10);
BEGIN
Select CustID INTO varCustID
From Address A
Join Meter M
on A.postCode = M.postCode
Where M.MeterID = :new.MeterID;
INSERT INTO BILL VALUES
(SEQBILLNO.NEXTVAL, SYSDATE, 'UNPAID' , 100 , varCustID , SEQREADNO.CURRVAL);
END;
If you need to query other record from READING table you have to use a combination of statement triggers, row trigger and a PLSQL collection. Good example of this is on AskTom.oracle.com
Make sure that you have the necessary permissions on all the tables and access to the sequences you're using in the insert.
I haven't done Oracle in awhile, but you can also try querying dba_errors (or all_errors) in order to try and get more information on why your SP isn't compiling.
Something to the tune of:
SELECT * FROM dba_errors WHERE owner = 'THEOWNER_OF_YOUR_SP';
Add exception handling in your trigger and see what is happening, by doing it would be easy for you to track the exceptions.
CREATE OR REPLACE TRIGGER AFTERINSERTCREATEBILL
AFTER INSERT
ON READING
FOR EACH ROW
DECLARE
varCustID Varchar(10);
BEGIN
-- your code
EXCEPTION
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.PUT_LINE(TO_CHAR(SQLERRM(-20299)));
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(TO_CHAR(SQLERRM(-20298)));
END;
we can combined insert and select statement
CREATE OR REPLACE TRIGGER AFTERINSERTCREATEBILL
AFTER INSERT
ON READING
FOR EACH ROW
DECLARE
varCustID Varchar(10);
BEGIN
insert into bill
values
select SEQBILLNO.NEXTVAL,
SYSDATE,
'UNPAID' ,
100 ,
CustID,SEQREADNO.CURRVAL
From Address A
Join Meter M
on A.postCode = M.postCode
Where M.MeterID = :new.MeterID;
END;
try the above code.

Getting the value that fired the Oracle trigger

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

Resources