update same record which fires a trigger - oracle

I want to update the same record which fires a trigger. I have done that using "BEFORE INSERT"
option. But note that I have use a transaction to rollback the operation if there is an any faliure.
CREATE OR REPLACE TRIGGER GANUKA.INTF_CONTROLLER_UPLOADER
BEFORE insert ON GANUKA.INTF_CONTROLLER for each row
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
max_id INTEGER;
stat VARCHAR2(32);
begin
select :new.id into max_id from dual;
select :new.status into stat from dual;
IF STAT = 'NEW' THEN --ONLY NEW UPLOADS WILL CONTINUE FOR PROCESS
:NEW.STATUS := 'STARTED';
max_id := GANUKA.BACKOFFICE_UPDATE(max_id); --PL/SQL function
:NEW.STATUS := 'COMPLETED';
ELSE
:NEW.STATUS := 'ABORTED';
:NEW.REMARKS :='STATUS IS NOT RECONGNIZED';
END IF;
COMMIT;
EXCEPTION
WHEN OTHERS
THEN
ROLLBACK;
RAISE;
end;
/
Problem is if there is an an any exception I want to update the record to set the state as 'Failed'. Can any one tell me how to do that.

I'm not sure why do you use autonomous transaction here and why do you have to commit/rollback in the trigger...

Does this do it?
CREATE OR REPLACE TRIGGER GANUKA.INTF_CONTROLLER_UPLOADER
BEFORE insert ON GANUKA.INTF_CONTROLLER for each row
DECLARE
max_id INTEGER;
stat VARCHAR2(32);
begin
max_id := :new.id;
stat := :new.status;
IF STAT = 'NEW' THEN --ONLY NEW UPLOADS WILL CONTINUE FOR PROCESS
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
max_id := GANUKA.BACKOFFICE_UPDATE(max_id); --PL/SQL function
COMMIT;
:NEW.STATUS := 'COMPLETED';
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
:new.status := 'FAILED';
END;
ELSE
:NEW.STATUS := 'ABORTED';
:NEW.REMARKS :='STATUS IS NOT RECONGNIZED';
END IF;
end;
/

Related

How we can specify that the TRG_2 trigger should be executed before the TRG_1 trigger by recreating the TRG_1 trigger using the execute clause?

I have created the two trigger, trigger 1 name TRIGGER_FOLLOWS_TEST_TRG_2 & trigger 2 name TRIGGER_FOLLOWS_TEST_TRG_1.
I want the TRIGGER_FOLLOWS_TEST_TRG_2 trigger to execute before the TRIGGER_FOLLOWS_TEST_TRG_1 trigger, by recreating the TRIGGER_FOLLOWS_TEST_TRG_1trigger .
create or replace TRIGGER TRIGGER_FOLLOWS_TEST_TRG_1
AFTER INSERT OR UPDATE
OF ISSA_STATUS_P, PRB_BEW_CODE
ON PROBE
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
EXECUTE TRIGGER_FOLLOWS_TEST_TRG_2
DECLARE
V_STATUS VARCHAR2(10);
V_BEW_CODE VARCHAR2(5);
BEGIN
IF INSERTING OR UPDATING THEN
V_STATUS := :NEW.ISSA_STATUS_P;
V_BEW_CODE := :NEW.PRB_BEW_CODE;
ELSE
V_STATUS := :OLD.ISSA_STATUS_P;
V_BEW_CODE := :OLD.PRB_BEW_CODE;
END IF;
IF (V_STATUS = 'PAF' AND V_BEW_CODE IS NULL) THEN
RAISE_APPLICATION_ERROR (-20011, 'Error: Status is finalized but assessment code is null');
END IF;
END TRIGGER_FOLLOWS_TEST_TRG_1;
and
create or replace TRIGGER TRIGGER_FOLLOWS_TEST_TRG_1
AFTER INSERT OR UPDATE
OF ISSA_STATUS_P, PRB_BEW_CODE
ON PROBE
DEFERRABLE INITIALLY DEFERRED
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
EXECUTE TRIGGER_FOLLOWS_TEST_TRG_2
DECLARE
V_STATUS VARCHAR2(10);
V_BEW_CODE VARCHAR2(5);
BEGIN
IF INSERTING OR UPDATING THEN
V_STATUS := :NEW.ISSA_STATUS_P;
V_BEW_CODE := :NEW.PRB_BEW_CODE;
ELSE
V_STATUS := :OLD.ISSA_STATUS_P;
V_BEW_CODE := :OLD.PRB_BEW_CODE;
END IF;
IF (V_STATUS = 'PAF' AND V_BEW_CODE IS NULL) THEN
RAISE_APPLICATION_ERROR (-20011, 'Error: Status is finalized but assessment code is null');
END IF;
END TRIGGER_FOLLOWS_TEST_TRG_1;
I have tried this:
create or replace TRIGGER TRIGGER_FOLLOWS_TEST_TRG_1
AFTER INSERT OR UPDATE
OF ISSA_STATUS_P, PRB_BEW_CODE
ON PROBE
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
EXECUTE TRIGGER_FOLLOWS_TEST_TRG_2
DECLARE
V_STATUS VARCHAR2(10);
V_BEW_CODE VARCHAR2(5);
BEGIN
IF INSERTING OR UPDATING THEN
V_STATUS := :NEW.ISSA_STATUS_P;
V_BEW_CODE := :NEW.PRB_BEW_CODE;
ELSE
V_STATUS := :OLD.ISSA_STATUS_P;
V_BEW_CODE := :OLD.PRB_BEW_CODE;
END IF;
IF (V_STATUS = 'PAF' AND V_BEW_CODE IS NULL) THEN
RAISE_APPLICATION_ERROR (-20011, 'Error: Status is finalized but assessment code is null');
END IF;
END TRIGGER_FOLLOWS_TEST_TRG_1;
When I create this trigger, it shows an error near " EXECUTE".

Conditional inserts and rollback

I have three insert statements A,b and C which are to be executed in sequence. If A fails, then C has to fail and vice-versa. How to handle this situation?
Table creation:
drop table mytab;
create table mytab(v varchar2(10));
Procedure with Autonomous Transaction: Autonomous transaction allows nested transaction to be committed even if the outer transaction is rolled back.
create or replace procedure sp_tranB as
pragma autonomous_transaction;--runs as a separate transaction and commits irrespective of outer transaction
begin
insert into mytab values('Insert B');
commit;
exception when others
then null;
end;
Scenario: All inserts succeed.
declare
a_status number;
begin
a_status := 0;
begin
insert into mytab values('Insert A');
--do not commit here. This allows rollback if C fails.
exception when others
then a_status := 1;
end;
begin
sp_tranB;
end;
if a_status = 0 then
begin
insert into mytab values('Insert C');
commit;
exception when others
then rollback;
end;
end if;
end;
select * from mytab;
output:
V
Insert A
Insert B
Insert C
truncate table mytab;
Scenario: A fails and prevents C
declare
a_status number;
begin
a_status := 0;
begin
insert into mytab values('Insert A too large');--A fails
--do not commit here. This allows rollback if C fails.
exception when others
then a_status := 1;
end;
begin
sp_tranB;
end;
if a_status = 0 then--C must not execute as A fails
begin
insert into mytab values('Insert C');
commit;
exception when others
then rollback;
end;
end if;
end;
select * from mytab;
Output:
V
Insert B
truncate table mytab;
Scenario: C fails and rollback A
declare
a_status number;
begin
a_status := 0;
begin
insert into mytab values('Insert A');
--do not commit here. This allows rollback if C fails.
exception when others
then a_status := 1;
end;
begin
sp_tranB;
end;
if a_status = 0 then
begin
insert into mytab values('Insert C too large');--C fail and....
commit;
exception when others
then rollback;
--...rollsback A
end;
end if;
end;
select * from mytab;
Output:
V
Insert B
Note: It is not advisable to suppress exceptions with "WHEN OTHERS NULL;". Do not use it in your applications. It is used here only to demonstrate the feature of autonomous transactions for this specific requirement.

Oracle PL/SQL - how do I run the same block of code for ALL exceptions?

Oracle 11g. This seems like it should be stupidly obvious, but I haven't seen an example. I have 2 exceptions which each need to write slightly different log messages, and then they should do the same UPDATE and CONTINUE.
Is there any way to structure the exception so I only need to type the UPDATE and CONTINUE statements once, while keeping the different logging?
FOR my_rec IN my_cursor
LOOP
BEGIN
...do some stuff
EXCEPTION
WHEN NO_DATA_FOUND THEN
log_detail.new('Skipping record - ID not found');
UPDATE my_table
SET operation_result = 'Failed'
WHERE my_id = my_rec.some_id;
CONTINUE;
WHEN OTHERS THEN
log_detail.new('Skipping record - unknown error');
UPDATE my_table
SET operation_result = 'Failed'
WHERE my_id = my_rec.some_id;
CONTINUE;
END;
END LOOP;
Did you try:
FOR my_rec IN my_cursor
LOOP
BEGIN
...do some stuff
EXCEPTION
WHEN OTHERS THEN
if sqlcode=-1403 then
log_detail.new('Skipping record - ID not found');
else
log_detail.new('Skipping record - unknown error');
end if;
UPDATE my_table
SET operation_result = 'Failed'
WHERE my_id = my_rec.some_id;
CONTINUE;
END;
END LOOP;
You could try:
DECLARE
vError VARCHAR2(1);
vMessage VARCHAR2(100);
BEGIN
FOR my_rec IN my_cursor LOOP
vError := 'N';
BEGIN
...do some stuff
EXCEPTION
WHEN NO_DATA_FOUND THEN
vError := 'S';
vMessage := 'Skipping record - ID not found';
WHEN OTHERS THEN
vError := 'S';
vMessage := 'Skipping record - unknown error';
END;
IF vError = 'S' THEN
log_detail.new(vMessage);
UPDATE my_table
SET operation_result = 'Failed'
WHERE my_id = my_rec.some_id;
CONTINUE;
END IF;
END LOOP;
END;

no_data_found exception in oracle pl/sql while using collection

DECLARE
TYPE EmpList IS TABLE OF varchar2(50) INDEX BY BINARY_INTEGER;
temp SYS_REFCURSOR;
v_temp varchar2(50);
v_emp EmpList;
BEGIN
v_emp (1) := 'gaurav';
v_emp (2) := 'manu';
open temp for select v_emp(level) from dual connect by level<=2;
loop
fetch temp into v_temp;
exit when temp%notfound;
DBMS_OUTPUT.put_line (v_temp);
end loop;
close temp;
--the below part works, then why not the above part dint works
for i in v_emp.first..v_emp.last
loop
dbms_output.put_line(v_emp(i));
end loop;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (SQLERRM);
END;
Can anyone please tell me why this collection dint work here??,It is giving me no_data_found exception.
the reason for failure is that
v_emp(level)
is evaluated (as its a variable) at runtime so would actually evaluate on all rows to
v_emp(0);
you could see this if you changed your array to
v_emp (0) := 'gaurav';
v_emp (1) := 'manu';
the proper way (in case you were not aware) is:
create TYPE EmpList IS TABLE OF varchar2(50);
/
and then :
v_emp := EmpList('gaurav', 'manu');
open temp for select column_value from table(v_emp);
Try This:
DECLARE
TYPE EmpList IS TABLE OF varchar2(50) INDEX BY BINARY_INTEGER;
temp SYS_REFCURSOR;
v_temp varchar2(50);
v_emp EmpList;
BEGIN
v_emp (0) := 'gaurav';
v_emp (1) := 'manu';
open temp for select v_emp(level) from dual connect by level<=2;
loop
fetch temp into v_temp;
exit when temp%notfound;
DBMS_OUTPUT.put_line ('v_temp' || v_temp);
end loop;
close temp;
--the below part works, then why not the above part dint works
for i in v_emp.first..v_emp.last
loop
dbms_output.put_line(v_emp(i));
end loop;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (SQLERRM);
END;

pl sql %NOTFOUND

I'm just wondering why this piece of code is not working. I don't have any supplier id=1 in my table.
DECLARE
VAR SUPP_NM VARCHAR(100);
VAR_SUPP_ID NUMBER := 1;
WHILE_VAR CHAR := 'Y';
BEGIN
SELECT SUPP_NM
INTO VAR_SUPP_NM
FROM TEST.SUPPLIER
WHERE SUPP_ID = VAR_SUPP_ID;
IF SQL%NOTFOUND THEN
DBMS_OUTPUT.PUT_LINE('SQL DATA NOT FOUND');
ELSIF SQL%FOUND THEN
DBMS_OUTPUT.PUT_LINE('DATA FOUND');
END IF;
END;
I get a 01403 error in Toad but not handled as sql%notfound.
Why isn't the sql%notfound working?
To catch the NO_DATA_FOUND exception rewrite your code as follows by adding exception section:
DECLARE
VAR_SUPP_NM VARCHAR2(100);
VAR_SUPP_ID NUMBER := 1;
WHILE_VAR CHAR := 'Y';
BEGIN
SELECT SUPP_NM
INTO VAR_SUPP_NM
FROM TEST.SUPPLIER
WHERE SUPP_ID = VAR_SUPP_ID;
DBMS_OUTPUT.PUT_LINE('DATA FOUND');
exception
when no_data_found
then DBMS_OUTPUT.PUT_LINE('SQL DATA NOT FOUND');
END;
Checking SQL%FOUND or SQL%NOTFOUND have no meaning in the case of select into statement, because if the select statement returns no rows it will always raise no_data_found exception, except, if that select statement invokes aggregate function, it will always return data or null if no rows has been selected.
Do not use varchar datatype, use varchar2 datatype instead.
Nicholas's answer is what you want if you want to use SELECT INTO. However, if it is more important that you are able to use %FOUND or %NOTFOUND, consider FETCHing from a cursor instead:
DECLARE
VAR SUPP_NM VARCHAR2(100);
VAR_SUPP_ID NUMBER := 1;
WHILE_VAR CHAR := 'Y';
CURSOR c1 IS
SELECT SUPP_NM
FROM TEST.SUPPLIER
WHERE SUPP_ID = VAR_SUPP_ID;
BEGIN
OPEN c1;
FETCH c1 INTO VAR_SUPP_NM;
IF c1%NOTFOUND THEN
DBMS_OUTPUT.PUT_LINE('SQL DATA NOT FOUND');
ELSIF c1%FOUND THEN
DBMS_OUTPUT.PUT_LINE('DATA FOUND');
END IF;
CLOSE c1;
END;
Nick's answer is correct.
In oracle documentation however it is stated that SQL%NOTFOUND works with SELECT INTO but before one could check SQL%NOTFOUND to be TRUE an error is generated called as no_data_found.
so to use SQL%NOTFOUND one first needs to hande no_data_found error.
DECLARE
VAR SUPP_NM VARCHAR(100);
VAR_SUPP_ID NUMBER := 1;
WHILE_VAR CHAR := 'Y';
BEGIN
BEGIN
SELECT SUPP_NM
INTO VAR_SUPP_NM
FROM TEST.SUPPLIER
WHERE SUPP_ID = VAR_SUPP_ID;
EXCEPTION
WHEN NO_DATA_FOUND THEN
null; -- or write something here if u want.
END;
IF SQL%NOTFOUND THEN
DBMS_OUTPUT.PUT_LINE('SQL DATA NOT FOUND');
ELSIF SQL%FOUND THEN
DBMS_OUTPUT.PUT_LINE('DATA FOUND');
END IF;
END;
So what I have done is added a inner BEGIN-END block enclosing the SELECT statement that generates no_data_found exception. After that you can check for the value of SQL%NOTFOUND.
You can read more about this in oracle docs.
Start from this active link in mytime : https://docs.oracle.com/cd/B28359_01/appdev.111/b28370/errors.htm#LNPLS00703

Resources