Exception handling for insert statements in plsql code - sql

if i have 3 insert statements in my plsql code.
lets assume them as insert_1, insert_2, insert_3.
my conditions be like : if insert_1 statement successfully executed then automatically insert_3 should be executed as well as if insert_3 executed successfully then insert_1 also should be executed automatically.
if both insert_1 and insert_3 fails then only insert_2 should be executed.
please write plsql code for this requirement.

You can create a package for this:
create a package and inside package body you try something like this.
create or replace PACKAGE BODY PKG_INSERT_QUERY AS
P_ERR_CODE number;
procedure finalPro
is
begin
P_ERR_CODE := 0;
insert into a values('a');
commit;
EXCEPTION WHEN OTHERS THEN ROLLBACK;
DBMS_OUTPUT.PUT_LINE('ERROR ' ||SQLERRM);
P_ERR_CODE := 1;
if(P_ERR_CODE < 1 )then
secondQ;
IF(P_ERR_CODE < 1) THEN
thirdQ;
END IF;
END IF;
end;
procedure secondQ
as
begin
insert into B values('B');
commit;
EXCEPTION WHEN OTHERS THEN ROLLBACK;
DBMS_OUTPUT.PUT_LINE('ERROR ' ||SQLERRM);
P_ERR_CODE := 2;
end;
procedure thirdQ
as
begin
insert into C values('C');
commit;
EXCEPTION WHEN OTHERS THEN ROLLBACK;
DBMS_OUTPUT.PUT_LINE('ERROR ' ||SQLERRM);
P_ERR_CODE := 3;
end;
end;

Related

how to solve these my error exception?

how to solve this error
create or replace package pg1
as
procedure p1(p_deptno in number);
type t is table of emp%rowtype
index by binary_integer;
end pg1;
create or replace package body pg1
as
procedure p1(p_deptno in number)
as
v_emp t;
v_dep exception;
begin
begin
select * bulk collect into v_emp from emp where deptno=p_deptno;
if p_deptno=10 then
raise v_dep;
end if;
for i in v_emp.first..v_emp.last
loop
insert into pg values(v_emp(i).empno, v_emp(i).ename, v_emp(i).job, v_emp(i).mgr, v_emp(i).hiredate, v_emp(i).sal, v_emp(i).comm, v_emp(i).deptno);
end loop;
exception
when v_dep then
raise_application_error(-20200,'my exception raised');
raise value_error;
end
when value_error then/*here getting error*/
dbms_output.put_line('value error');
end;
end p1;
end pg1;
end;
23/1 PLS-00103: Encountered the symbol "WHEN" when expecting one
of
the following:
;
First always try to evaluate what error does oracle throws. Oracle errors are very descriptive inmost of the cases. Here if you see carefully it always points to the exact line number too. Hope you will try to debug next time onwards :)
CREATE OR REPLACE PACKAGE pg1
AS
PROCEDURE p1(
p_deptno IN NUMBER);
type t
IS
TABLE OF emp%rowtype INDEX BY binary_integer;
END pg1;
CREATE OR REPLACE PACKAGE body pg1
AS
PROCEDURE p1(
p_deptno IN NUMBER)
AS
v_emp t;
v_dep EXCEPTION;
BEGIN
BEGIN
SELECT * bulk collect INTO v_emp FROM emp WHERE deptno=p_deptno;
IF p_deptno=10 THEN
raise v_dep;
END IF;
FOR i IN v_emp.first..v_emp.last
LOOP
INSERT
INTO pg VALUES
(
v_emp(i).empno,
v_emp(i).ename,
v_emp(i).job,
v_emp(i).mgr,
v_emp(i).hiredate,
v_emp(i).sal,
v_emp(i).comm,
v_emp(i).deptno
);
END LOOP;
EXCEPTION
WHEN v_dep THEN
raise_application_error(-20200,'my exception raised');
raise value_error;
END; -- Missed semi colon here
WHEN value_error THEN
dbms_output.put_line('value error');
END;
END p1;
END pg1;
END;

sql package creating error

I'm trying to create a code in which i delete a student from my table by specifying his nr_matr, but if i don't have that nr_matr in my table then i want to trow an exception.
this is my code:
CREATE OR REPLACE PACKAGE manager_faculty IS
PROCEDURE delete_stud (nr_matr student.nr_matricol%type);
END manager_faculty;
/
CREATE OR REPLACE PACKAGE BODY manager_faculty IS
PROCEDURE delete_stud (nr_matr student.nr_matricol%type) IS
BEGIN
DELETE from student
WHERE nr_matricol=nr_matr;
EXCEPTION
WHEN no_data_found THEN
SELECT COUNT(*) INTO counter FROM student WHERE nr_matricol=nr_matr;
IF counter = 0 THEN
raise_application_error (-20001, 'There is no student with the number' || nr_matr);
END IF;
END delete_stud;
END manager_faculty;
/
set serveroutput on;
BEGIN
manager_faculty.delete_stud(125);
END;
/
When i'm trying to compile my code it says that the package body was created whit compilation errors. What am i doing wrong?
The error is PLS-00201: identifier 'COUNTER' must be declared and you can find this out by running SHOW ERRORS; after trying to compile your package body.
You can fix it like this:
CREATE OR REPLACE PACKAGE BODY manager_faculty IS
PROCEDURE delete_stud (nr_matr student.nr_matricol%type)
IS
counter INT;
BEGIN
DELETE FROM student
WHERE nr_matricol=nr_matr;
EXCEPTION
WHEN no_data_found THEN
SELECT COUNT(*)
INTO counter
FROM student
WHERE nr_matricol=nr_matr;
IF counter = 0 THEN
raise_application_error (
-20001,
'There is no student with the number' || nr_matr
);
END IF;
END delete_stud;
END manager_faculty;
/
SHOW ERRORS;
However, the code won't run as you expect as DELETE FROM will not throw an exception if it does not delete any rows. You will need to check SQL%ROWCOUNT:
CREATE OR REPLACE PACKAGE BODY manager_faculty IS
PROCEDURE delete_stud (nr_matr student.nr_matricol%type)
IS
BEGIN
DELETE from student
WHERE nr_matricol=nr_matr;
IF SQL%ROWCOUNT = 0 THEN
raise_application_error (
-20001,
'There is no student with the number' || nr_matr
);
END IF;
END delete_stud;
END manager_faculty;
/
Aside from using SQL%ROWCOUNT as answered by MTO, you can also use SQL%NOTFOUND.
%NOTFOUND yields TRUE if an INSERT, UPDATE, or DELETE statement affected no rows, or a SELECT INTO statement returned no rows. Otherwise, it yields FALSE.
CREATE OR REPLACE PACKAGE BODY manager_faculty IS
PROCEDURE delete_stud (nr_matr student.nr_matricol%type)
IS
BEGIN
DELETE from student
WHERE nr_matricol=nr_matr;
IF SQL%NOTFOUND THEN
raise_application_error (
-20001,
'There is no student with the number' || nr_matr
);
END IF;
END delete_stud;
END manager_faculty;
You can read here, if you want to know other attributes of SQL Cursor.

Oracle not able to insert exception into table

I have below procedure where i am trying to track the exceptions into I_Log table.To test whether its working or not I have made a ORA-00933: SQL command not properly ended error in my query where I am trying to insert into I_OPTION table. When i run this procedure the dbms output line is printing the error below but its not getting inserted into I_Log table:
OTHERS exception in EXT_I_OPTION - ID:1000196-933----ORA-00933: SQL command not properly ended
Below is my procedure:
CREATE OR REPLACE PROCEDURE
"EXT_I_OPTION"(in_id IN NUMBER DEFAULT 0)
AS
err_code VARCHAR(100);
err_msg VARCHAR(100);
in_event_id NUMBER;
in_db_link VARCHAR2(50);
in_env_id NUMBER;
l_sql VARCHAR2(5000);
l_sql1 VARCHAR2(5000);
BEGIN
FOR I_row IN I_cur
LOOP
l_sql2 := INSERT INTO I_OPTION(ID)
select DISTINCT(SO.ID)
)
from Icard I;
END LOOP;
EXCEPTION WHEN OTHERS THEN
err_code := SQLCODE;
err_msg := SUBSTR(SQLERRM, 1, 200);
INSERT INTO I_log (I_ID)
VALUES (i_id);
RAISE;
COMMIT;
END ext_I_option;
It seems that you have a RAISE before COMMIT; this way, the error will be raised before doing COMMIT, so you don't find data in your log table.
According to suggestions, you should define a procedure to handle your log table:
CREATE OR REPLACE procedure i_LOG (...) AS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
Insert into I_LOG(...);
COMMIT;
END;
/
This procedure runs in a separate transaction, so it only does commit of log data, with no conflict with data you modify in your main procedure.
Then you should modify your error handling in this way, avoiding COMMIT statement, that can be really dangerous, saving partial, unconsistent data:
DBMS_OUTPUT.PUT_LINE('OTHERS exception in EXT_I_OPTION - ID:'||to_char(ID) || err_code || '----' || err_msg );
ins_I_LOG(...);
RAISE;

How to create a procedure in an oracle sql script and use it inside the script?

I want to create a script for my oracle DB, which drops tables. If the table does not exist, the script won't exit as fail, just print a text: "does not exists".
The script is the following:
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE mytable';
DBMS_Output.Put_Line(' table dropped');
EXCEPTION WHEN OTHERS THEN
IF SQLCODE = -942 THEN
DBMS_Output.Put_Line(' table not exists');
ELSE
DBMS_Output.Put_Line(' Unknown exception while dropping table');
RAISE;
END IF;
END;
I want to drop a lot of table in one script, and I don't want to write these lines more than once.
Is there any way, to write it to a procedure or function which gets a parameter (the name of the table), and call this procedure in that script?
Maybe something like this:
drop_table_procedure('mytableA');
drop_table_procedure('mytableB');
Or maybe a procedure, which gets an undefined size list (like in java: String ... table names):
drop_tables_procedure('mytableA','mytableB');
Please give me some examples.
Thanks!
Yes, you can declare a "temporary" procedure in an anonymous PL/SQL block:
DECLARE
PROCEDURE drop_if_exists(p_tablename VARCHAR)
IS
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE '||p_tablename;
DBMS_Output.Put_Line(' table dropped');
EXCEPTION WHEN OTHERS THEN
IF SQLCODE = -942 THEN
DBMS_Output.Put_Line(' table not exists');
ELSE
DBMS_Output.Put_Line(' Unknown exception while dropping table');
RAISE;
END IF;
END;
BEGIN
drop_if_exists('TABLE_1');
drop_if_exists('TABLE_2');
END;
/
in execute immediate you need add name of database object.
here's the script
create table t1 (col1 int);
create table t2 (col1 int);
create procedure drop_my_table(av_name varchar2)
as
begin
EXECUTE IMMEDIATE 'DROP TABLE '||av_name;
DBMS_Output.Put_Line(' table dropped');
EXCEPTION WHEN OTHERS THEN
IF SQLCODE = -942 THEN
DBMS_Output.Put_Line(' table not exists');
ELSE
DBMS_Output.Put_Line(' Unknown exception while dropping table');
RAISE;
END IF;
end drop_my_table;
declare
type array_t is varray(2) of varchar2(30);
atbls array_t := array_t('t1', 't2');
begin
for i in 1..atbls.count loop
drop_my_table(atbls(i));
end loop;
end;
You can use below one also
create or replace PROCEDURE drop_if_exists(p_tablename in VARCHAR)
IS
v_var1 number;
begin
select 1 into v_var1 from user_tables where table_name=upper(p_tablename);
if v_var1=1
then
EXECUTE IMMEDIATE 'DROP TABLE '||p_tablename;
DBMS_Output.Put_Line(' table dropped');
else
DBMS_Output.Put_Line(' table not exist');
end if;
exception
when others then
DBMS_Output.Put_Line(' Unknown exception while dropping table');
RAISE;
end;
Call procedure
begin
drop_if_exists('emp');
end;
/

Assign function to a variable and use it within procedure

I am getting a problem with using 'Next Sequence Values' inside a procedure.
I have my 'external' function to return the Next Value of Sequence.
Inside my procedure, i want to assign the values of that sequence into a variable
and use that variable inside my cursor (since i am using a union statement in my cursor).
But it is not working.
CREATE OR REPLACE Procedure HR.insert_TBL_APP is
--declare variables for insert
v_TA_SNO VARCHAR2(10);
v_TA_SEQNO VARCHAR2(6);
v_TA_DESC VARCHAR2(10);
--declare variable to store the sequence number
var_TaSeqno varchar2(6);
-- Validation
v_check VARCHAR2 (10 Byte);
err_code varchar2(50);
err_msg varchar2(100);
v_table_name varchar2(50):='TBL_APP';
error_found exception;
cursor c1 is
select distinct TA_SNO,
TA_SEQNO,
TA_DESC
from (
SELECT hdr.FIRST_NO TA_SNO,
var_TaSeqno TA_SEQNO, -- using variable to assign the sequence no
hdr.descrip TA_DESC
FROM
FORMS_HDR hdr
WHERE
hdr.seco_name = 'TST121'
union
SELECT hdr.FIRST_NO TA_SNO,
var_TaSeqno TA_SEQNO, -- using variable to assign the sequence no
hdr.descrip TA_DESC
FROM
FORMS_HDR hdr
WHERE
hdr.seco_name = 'TST122');
begin
if c1%isopen then
close c1;
end if;
v_check:=null;
FOR i IN c1 LOOP
--assign variables for insert
v_TA_SNO := i.TA_SNO;
v_TA_SEQNO := i.TA_SEQNO;
v_TA_DESC := i.TA_DESC;
begin
-- calling the Function taSeqNoFunc and assign the
--sequence No into the variable var_TaSeqno
var_TaSeqno := HR.taSeqNoFunc();
select TA_SNO
into v_check
from TBL_APP a
where TA_SNO = i.TA_SNO
and TA_SEQNO =i.TA_SEQNO;
exception
when no_data_found then
--insert into target table
INSERT INTO TBL_APP (TA_SNO,
TA_SEQNO,
TA_DESC
)
values (v_TA_SNO,
v_TA_SEQNO,
v_TA_DESC
);
when others then
raise error_found;
end ;
end loop;
exception when error_found then
rollback;
err_code := SQLCODE;
err_msg := SUBSTR(SQLERRM, 1, 200);
insert into TA_ERROR_LOG values (v_check,v_table_name,'An error
was encountered '||err_code||':'||err_msg,sysdate);
commit;
raise_application_error(err_code,err_msg);
end;
/
The error finally goes into raise_application_error near the end:
"ORA-21000: error number argument to raise_application_error of 1 is out of range"
Please help me. Thank you.
The raise_application_error() procedure is an Oracle PL/SQL built-in. It's provided so what we can associate a custom message to a user-defined exception. User-defined exceptions must have numbers in the range -20999 to -20000. Find out more.
You are getting this error because of this code in your inner EXCEPTION block:
when others then
raise error_found;
You are raising a user-defined exception but one you haven't associated to an error number with the EXCEPTION_INIT pragma. Find out more. So, Oracle defaults to SQLCODE = 1, SQLERRM = 'User-Defined Exception'.
Clearly 1 is outside the permitted range of raise_application_error(). Hence the error when you come to the outer EXCEPTION block.
The way to avoid this is to remove the ERROR_FOUND exception and rely on Oracle's default exception handling.
In the innermost block you want to re-raise any exception except NO_DATA_FOUND. The simplest way to do that is remove the WHEN OTHERS clause. Then, in the outer block you will have meaningful values for SQLCODE and SQLERRM which you can log. Then just use RAISE to propagate them up the stack....
exception
when others then
rollback;
err_code := SQLCODE;
err_msg := SUBSTR(SQLERRM, 1, 200);
insert into TA_ERROR_LOG values (v_check,v_table_name,'An error
was encountered '||err_code||':'||err_msg,sysdate);
commit;
raise;
end;
Not only will you not get an error from raise_application_error(), your log will contain a useful error number and message.
Incidentally, it is bad practice to use ROLLBACK and COMMIT like that in an EXCEPTION block. A better approach is to write a logging procedure which is covered by the AUTONOMOUS_TRANSACTION pragma. That way the logging won't interfere with the wider transaction. Find out more.
The error number you pass to the raise_application_error procedure must be a negative integer in the range -20000..-20999.
For user-defined exceptions SQLCODE returns always +1, so you're passing +1 as
the error number to the raise_application_error procedure and that's out of range.
I have posted the answer. It can be further improved.
The pragma exception_init is used to catch the error (in my case - Integrity Constraint).
I have removed the function to call 'next sequence value' since it can be called directly just before performing the insert.
#APC Thanks :)
CREATE OR REPLACE Procedure HR.insert_TBL_APP is
--declare variables for insert
v_TA_SNO VARCHAR2(10);
v_TA_SEQNO VARCHAR2(6);
v_TA_DESC VARCHAR2(10);
-- Validation
v_check VARCHAR2 (10 Byte);
err_code varchar2(50);
err_msg varchar2(200);
v_table_name varchar2(50):='TBL_APP';
error_found exception;
parent_not_found exception; -- use it to catch the Integrity Constraint
pragma exception_init(parent_not_found, -2291);
cursor c1 is
select distinct TA_SNO,
TA_SEQNO,
TA_DESC
from (
SELECT hdr.FIRST_NO TA_SNO,
-1 TA_SEQNO, -- assign a dummy value as sequence no
hdr.descrip TA_DESC
FROM
FORMS_HDR hdr
WHERE
hdr.seco_name = 'TST121'
union
SELECT hdr.FIRST_NO TA_SNO,
-2 TA_SEQNO, -- assign a dummy value as sequence no
hdr.descrip TA_DESC
FROM
FORMS_HDR hdr
WHERE
hdr.seco_name = 'TST122');
begin
if c1%isopen then
close c1;
end if;
v_check:=null;
FOR i IN c1 LOOP
--assign variables for insert
v_TA_SNO := i.TA_SNO;
v_TA_SEQNO := i.TA_SEQNO;
v_TA_DESC := i.TA_DESC;
begin
--var_TaSeqno := HR.taSeqNoFunc(); --the variable will not be used
select TA_SNO
into v_check
from TBL_APP a
where TA_SNO = i.TA_SNO
and TA_SEQNO =i.TA_SEQNO;
exception
when no_data_found then
Begin -- added line to use exception
--insert into target table
INSERT INTO TBL_APP (TA_SNO,
TA_SEQNO,
TA_DESC
)
values (v_TA_SNO,
TA_SEQNO.nextval, --insert the nextval directly
v_TA_DESC
);
--when the integrity constraint (parent key) error is thrown, insert into the TA_ERROR_LOG
exception
when parent_not_found then
rollback;
err_msg := SUBSTR(SQLERRM, 1, 200);
insert into TA_ERROR_LOG values (v_check,v_table_name, err_msg, sysdate);
commit;
end; -- end begin for using the exception
when others then
raise error_found;
end ;
end loop;
exception when error_found then
rollback;
err_code := SQLCODE;
err_msg := SUBSTR(SQLERRM, 1, 200);
insert into TA_ERROR_LOG values (v_check,v_table_name, err_msg, sysdate);
commit;
raise_application_error(err_code,err_msg);
end;