Continue on error in loop - oracle

The loop below is callign a proc that does various 'things'
If it should throw an exception it also 'raises' it. I want to catch it and ignore it and allow the loop to continue processing the next value in the array.
Thanks
WHILE indx IS NOT NULL LOOP
table_dump_csv(tableList(indx), tableList(indx) || '.csv');
indx := tableList.NEXT(indx);
END LOOP;

One possible approach...
WHILE indx IS NOT NULL LOOP
BEGIN
table_dump_csv(tableList(indx), tableList(indx) || '.csv');
EXCEPTION
WHEN OTHERS THEN
-- Handle/Ignore the exception as appropriate
END;
indx := tableList.NEXT(indx);
END LOOP;
Alternatively you could change the procedure into a function which returns a success/failure code.

Related

How to handle different exceptions in PL/SQL differently?

My stored-procedure is looping executing different statements. I want to handle the following situations:
When the statement returns nothing (no_data_found), I want to quietly skip the rest of the loop (continue).
When the statement causes an error of any type, I want to report it, and then skip the rest of the loop (continue);
When the statement finds rows, I want to report it.
The code looks like:
...
LOOP
stmt := 'select * ......';
BEGIN
EXECUTE IMMEDIATE stmt;
EXCEPTION
WHEN NO_DATA_FOUND THEN NULL;
WHEN OTHERS THEN
dbms_out.put_line(stmt || ': ' || SQLCODE);
CONTINUE;
END;
dbms_out.put_line('Found! Use: ' || stmt);
END LOOP;
The above elicits no errors, but the Found-line is printed for every loop-iteration, including for statements, that yield no results...
Why is the CONTINUE-directive ignored -- am I wrong expecting the directive to be obeyed for any exception -- be it NO_DATA_FOUND or anything else?
In your exception block, the action for your NO_DATA_FOUND handler is NULL - so it executes the NULL statement (i.e. does nothing) and falls out of the BEGIN-END block, hitting the dbms_out.put_line('Found! Use: ' || stmt); statement. The only handler which will execute CONTINUE; is the WHEN OTHERS.
One way to get the behavior you describe is to do a SELECT COUNT(*)... into a numeric variable and then just check to see how many rows are returned:
DECLARE
csr SYS_REFCURSOR;
nCount NUMBER;
BEGIN
LOOP
stmt := 'SELECT COUNT(*) FROM (SELECT * from ... WHERE ...)';
OPEN csr FOR stmt;
FETCH csr INTO nCount;
CLOSE csr;
IF nCount > 0 THEN
dbms_out.put_line('Found! Use: ' || stmt);
ELSE
dbms_out.put_line(stmt || ': ' || SQLCODE);
END IF;
END LOOP;
END;
Of course this is not really valid as there's no way for the value of stmt to change, but I suspect your "real" code handles that.

PLSQL Exception handling in GET_FILE

Trying to handle exception if the input file received has invalid records or no data. The below exception runs in loop even though the input file has only 1 record.
LOOP
BEGIN
UTL_FILE.GET_LINE(a_UIN_input_file,a_UIN_file);
a_rec := substr(a_uin_file,1,9);
EXCEPTION
WHEN NO_DATA_FOUND THEN
a_error_file := utl_file.fopen('TAMUOUT','PWT_TEST5_ERROR.txt','w');
utl_file.put_line(a_error_file,'Bad UIN Read ' ||SQLERRM||'\n');
utl_file.fclose(a_error_file);
-- EXIT;
END;
END LOOP;
FOR rec IN get_details_4_uin_c(a_rec) LOOP
a_pidm :=fwt_get_pidm_from_uin(a_rec);
a_bill_hours := fwt_get_enrolled_hours(a_pidm,in_term_code);
utl_file.put_line(a_out_file,a_parm,
autoflush=>TRUE);
END LOOP;
utl_file.fclose(a_uin_input_file);
UTL_FILE.GET_LINE raises the NO_DATA_FOUND exception when you have reached the end of the file and then keep on trying to read more.
So your exception handler for NO_DATA_FOUND should exit the loop. But within the loop, if you read a line successfully, then run your loop on that.
I believe the code believe will help you get to your solution.
BEGIN
LOOP
BEGIN
UTL_FILE.get_line (a_uin_input_file, a_uin_file);
a_rec := SUBSTR (a_uin_file, 1, 9);
FOR rec IN get_details_4_uin_c (a_rec)
LOOP
a_pidm := fwt_get_pidm_from_uin (a_rec);
a_bill_hours := fwt_get_enrolled_hours (a_pidm, in_term_code);
UTL_FILE.put_line (a_out_file, a_parm, autoflush => TRUE);
END LOOP;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
UTL_FILE.fclose (a_uin_input_file);
EXIT;
END;
END LOOP;
END;

How to handle cursor exception when the select query returns "zero" records

How to handle cursor exception when the select query returns "zero" records
I have a cursor in a procedure, and after cursor initialization I'm iterating through the cursor to access the data from it.
But the problem is when the cursor select query returns 0 records then it throws exception
ORA-06531: Reference to uninitialized collection.
How to handle this exception?
---procedure code
create or replace PROCEDURE BIQ_SECURITY_REPORT
(out_chr_err_code OUT VARCHAR2,
out_chr_err_msg OUT VARCHAR2,
out_security_tab OUT return_security_arr_result ,
)
IS
l_chr_srcstage VARCHAR2 (200);
lrec return_security_report;
CURSOR cur_security_data IS
SELECT
"ID" "requestId",
"ROOM" "room",
"FIRST_NAME" "FIRST_NAME",
"LAST_NAME" "LAST_NAME",
FROM
"BI_REQUEST_CATERING_ACTIVITY" ;
TYPE rec_security_data IS TABLE OF cur_security_data%ROWTYPE
INDEX BY PLS_INTEGER;
l_cur_security_data rec_security_data;
begin
OPEN cur_security_data;
LOOP
FETCH cur_security_data
BULK COLLECT INTO l_cur_security_data
LIMIT 1000;
EXIT WHEN l_cur_security_data.COUNT = 0;
lrec := return_security_report();
out_security_tab := return_security_arr_result(return_security_report());
out_security_tab.delete;
FOR i IN 1 .. l_cur_security_data.COUNT
LOOP
BEGIN
l_num_counter := l_num_counter + 1;
lrec := return_security_report();
lrec.requestid := l_cur_security_data(i).requestId ; lrec.room := l_cur_security_data(i).room ; lrec.firstName := l_cur_security_data(i).firstName ;
IF l_num_counter > 1
THEN
out_security_tab.extend();
out_security_tab(l_num_counter) := return_security_report();
ELSE
out_security_tab := return_security_arr_result(return_security_report());
END IF;
out_security_tab(l_num_counter) := lrec;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.PUT_LINE('Error occurred : ' || SQLERRM);
END;
END LOOP;
END LOOP;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.PUT_LINE ('HERE INSIIDE OTHERS' || SQLERRM);
END;
Can you please explain how handle it.
You must be using out_security_tab, which is an output parameter in some other code where the procedure is called.
In your procedure, If cursor returns zero rows then the loop will not be executed and your code will not even initialize the out_security_tab which will lead to the error that you are facing.
There is a simple way to avoid:
initialize out_security_tab outside the loop -- which will definitely initialize it
You can create one out variable containing details as Y or N based on if cursor rows count -- Not recommended
Cheers!!

Oracle Function that return table of number problems and performance

I have (sometimes) a memory block in my oracle database that turn crasy... a lot of session sundenless block each other and the probleme is in a function that return a table of number and is use in another procedure.
Edit : Sessions is 'blocked' with Read By Other Session Wait Event
First, my table of number :
CREATE OR REPLACE TYPE liste_lots as TABLE OF number(10)
and in large the function who populate the table :
function get_ot_idem_cursor( .. ) return liste_lots is
res_type liste_lots;
p_restriction_level number;
cursor curs_lvl_1 is select [...] ;
row_lvl_1 curs_lvl_1%rowtype;
cursor curs_lvl_0 is select [...] ;
row_lvl_0 curs_lvl_0%rowtype;
begin
res_type := liste_lots();
p_restriction_level := get_edi_line_restriction(p_edi_line);
if p_restriction_level = 1 then
open curs_lvl_1;
loop
fetch curs_lvl_1 into row_lvl_1;
exit when curs_lvl_1%notfound;
begin
res_type.extend;
res_type(res_type.last) := row_lvl_1.lot_id;
exception
when others then
dbms_output.put_line('problème get_ot_idem_cursor ');
dbms_output.put_line(sqlerrm);
close curs_lvl_1;
end;
end loop;
close curs_lvl_1;
else
open curs_lvl_0;
loop
fetch curs_lvl_0 into row_lvl_0;
exit when curs_lvl_0%notfound;
begin
res_type.extend;
res_type(res_type.last) := row_lvl_0.lot_id;
exception
when others then
dbms_output.put_line('problème get_ot_idem_cursor ');
dbms_output.put_line(sqlerrm);
close curs_lvl_0;
end;
end loop;
close curs_lvl_0;
end if;
return res_type;
exception
when others then
if curs_lvl_0%isopen then
close curs_lvl_0;
end if;
if curs_lvl_1%isopen then
close curs_lvl_1;
end if;
end;
and is used on another part like that :
liste_ots := get_ot_idem_cursor(v_lot, v_sr_ligne_lot.id );
select min(l.lot_id) into result
from lot l
where l.des_tiers_id = p_pf_tiers_id
and l.lot_nature = 'POS'
and l.exp_tiers_id = v_sr_ligne_lot.ramasse_tiers_id
and ot_id in ((select * from TABLE(liste_ots)))
and l.lot_datheurcharg > sysdate - 3;
When the db become crasy (session block, very slow) this is the part of the code who is pointed :
select * from TABLE(liste_ots)
the problem is not all the time, then if you have any idea or advise...
thanks in advance (sorry for my bad english)
Use a bulk collect instead of a plain loop (fetching records one by one) as there is no additional logic done in the loop. In general, always avoid switching a context (SQL to/from PL/SQL)
open curs_lvl_1;
fetch curs_lvl_1 bulk collect into res_type;
close curs_lvl_1;

How can I modify my PL/SQL procedure to go to my exception handling?

I am using SQL developer to write a procedure.
The objective is to get the name of the drainage system from one table and get the count of how much the drainage system name code appears in another table.
My procedure works, but when I enter an incorrect value, it does not go to the exception section. For example, when I input ‘Mexico River’, this name does not exist in the table. So, I want my exception section to realize that this is an incorrect value being entered.
My question is how do I modify my code, so it can detect incorrect values and go to my exception section.
Below is a snippet of my code:
PROCEDURE number_of_rivers --second procedure with 1 parameter
(input_sysName IN TBLDrainage.DRAINAGE_SYS%TYPE)
is
-- Create a cursor
cursor c_river is
select code, drainage_sys
from TBLDRAINAGE
where DRAINAGE_SYS = input_sysName;
v_rivercount Number;
r_variable c_river %rowtype;
Begin
FOR r_variable in c_river
loop
select count (Drainage_sys) into v_rivercount
from TBLRIVER
where DRAINAGE_SYS = r_variable.code;
DBMS_OUTPUT.PUT_LINE (UPPER(input_sysName) || ' has ' || v_rivercount || ' river(s) in the drainage system.');
end loop;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE ('Error: Please enter a valid drainage system name');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE ('Error in finding system');
END ;
The CURSOR..FOR loop has the property of executing zero or more times. It doesn't throw NO_DATA_FOUND.
There are a couple of solutions. One is to include a count inside the loop, and raise an exception afterwards.
l_count := 0;
FOR r_variable in c_river
loop
....
l_count := l_count + 1;
end loop;
if l_count = 0 then
raise NO_DATA_FOUND;
end if;
The other would be to validate the input parameter at the start of your program.
begin
open c_river;
fetch c_river into r_variable;
if c_river%notfound then
raise NO_DATA_FOUND;
else
select count (Drainage_sys)
into v_rivercount
from TBLRIVER
where DRAINAGE_SYS = r_variable.code;
DBMS_OUTPUT.PUT_LINE (UPPER(input_sysName) || ' has ' || v_rivercount || ' river(s) in the drainage system.');
end if;
close c_river;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE ('Error: Please enter a valid drainage system name');
close c_river;
END ;
In this solution I have removed the loop, because I would expect a look-up on drainage system should be unique and return one record. Please re-instate the loop if your data model isn't like that.
I have retained your names for the cursor and its row variables but you should re-name them. They are used for selecting drainage systems not rivers, and their names ought to reflect that. Discipline in naming things is a useful habit to acquire, as misleading variable names will cause confusion in larger chunks of code.
Also, swallowing exceptions like this is very bad:
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE ('Error in finding system');
Oracle has thousands of error messages: it better to do nothing with the error message than to throw it away.

Resources