How to populate TABLE OF RECORDS with rows of 2 levels parent-child - oracle

I have a table with rows describing a tree, columns are:
(column child_num is unique and used as primary key)
TABLE items_tree (
child_num number,
parent_ref varchar2(10),
child_ref varchar2(10)
);
TYPE item_rec_type IS RECORD (
item_id NUMBER,
spaces_number NUMBER,
parent_ref VARCHAR2(10),
child_ref VARCHAR2(10)
);
TYPE tree_table_type IS TABLE OF item_rec_type%ROWTYPE
INDEX BY BINARY_INTEGER;
table_tree tree_table_type; -- table of all items
Example data for table items_tree (values of child_num are not relevant):
parent_ref child_ref
---------------------------
null Abraham
Abraham Isaac
Abraham Ishmael
Isaac Jakob
Jakob Yehuda
Jakob Josef
Jakob Benjamin
Yehuda David
Josef Efraim
Josef Menashe
David Solomon
Solomon Isaiah
Isaiah Jeremiah
I need to populate table_tree records from items_tree table. To do so, I am using a package, the item_rec_type, tree_table_type, table_tree are defined in it and two procedures: print_tree which retrieves the ROOT items of the tree, starts the process and prints the tree from table_tree. Second procedure get_items_by_parent_recursively is recursive procedure that retrieves all the items or a parent item, e.g. calling get_items_by_parent_recursively('Abraham') will add Isaac and Ishmael to table_tree.
The cursor is declared in the package body:
CURSOR get_children_cur(c_parent in varchar2(10))
IS
SELECT parent_ref, child_ref
FROM items_tree
WHERE parent_ref = c_parent
ORDER BY 1, 2;
The code in get_items_by_parent_recursively that retrieves the items for the parent:
procedure get_items_by_parent_recursively(p_parent in VARCHAR2(10), p_spaces_number in NUMBER )
AS
l_spaces_number NUMBER := 0;
l_child VHARCHAR2(10);
l_parent VHARCHAR2(10);
BEGIN
l_spaces_number := p_spaces_number + 3;
OPEN get_children_cur(p_parent);
LOOP
FETCH get_children_cur INTO l_parent, l_child;
EXIT WHEN get_children_cur%NOTFOUND;
IF (l_child is not null) THEN
v_row_number := v_row_number + 1;
tree_table(v_row_number).row_num := v_row_number;
tree_table(v_row_number).spaces_number := l_spaces_number;
tree_table(v_row_number).parent_ref := l_parent;
tree_table(v_row_number).child_ref := l_child;
-- Calling procedure recursively
get_items_by_parent_recursively( l_child, l_spaces_number );
END IF;
END LOOP;
CLOSE get_children_cur;
EXCEPTION
WHEN CURSOR_ALREADY_OPEN THEN
DBMS_OUTPUT.put_line(' Exception -- CURSOR_ALREADY_OPEN');
WHEN INVALID_CURSOR THEN
DBMS_OUTPUT.put_line(' Exception -- INVALID_CURSOR');
WHEN INVALID_NUMBER THEN
DBMS_OUTPUT.put_line(' Exception -- INVALID_NUMBER');
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.put_line(' Exception -- NO_DATA_FOUND');
WHEN PROGRAM_ERROR THEN
DBMS_OUTPUT.put_line(' Exception -- PROGRAM_ERROR');
WHEN ROWTYPE_MISMATCH THEN
DBMS_OUTPUT.put_line(' Exception -- ROWTYPE_MISMATCH');
WHEN STORAGE_ERROR THEN
DBMS_OUTPUT.put_line(' Exception -- STORAGE_ERROR');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.put_line(' Exception -- TOO_MANY_ROWS');
WHEN VALUE_ERROR THEN
DBMS_OUTPUT.put_line(' Exception -- VALUE_ERROR');
END get_items_by_parent_recursively;
Running this procedure I am getting the exception: CURSOR_ALREADY_OPEN.
I have searched for a reply, but none came close to what I need. I will appreciate any ideas.
I will try to make the cursor get_children_cur part of the recursive procedure.

As #vmachan said, you need to move the cursor definition into the procedure. While you have it in the package specification or body, but outside the procedure, there is one instance of it which is global to the session. Each call to your procedure attempts to open the same cursor; the initial call from print_tree succeeds, and your table is populated with 'Abraham'; but then the recursive call tries to re-open it and gets the CURSOR_ALREADY_OPEN exception, and stops.
Moving the cursor into the procedure means each call/iteration has its own independent copy. Cleaning up naming and various other issues, this then works:
procedure get_items_by_parent(p_parent in VARCHAR2, p_spaces_number in NUMBER)
AS
l_spaces_number NUMBER := 0;
l_child VARCHAR2(10);
l_parent VARCHAR2(10);
CURSOR get_children_cur(p_parent in varchar2) IS
SELECT parent_item, child_item
from items_tree
where parent_item = p_parent
or (p_parent is null and parent_item is null);
BEGIN
l_spaces_number := p_spaces_number + 3;
OPEN get_children_cur(p_parent);
LOOP
FETCH get_children_cur INTO l_parent, l_child;
EXIT WHEN get_children_cur%NOTFOUND;
IF (l_child is not null) THEN
v_row_number := v_row_number + 1;
table_tree(v_row_number).item_id := v_row_number;
table_tree(v_row_number).spaces_number := l_spaces_number;
table_tree(v_row_number).parent_item_ref := l_parent;
table_tree(v_row_number).item_ref := l_child;
-- Calling procedure recursively
get_items_by_parent( l_child, l_spaces_number );
END IF;
END LOOP;
CLOSE get_children_cur;
EXCEPTION
WHEN CURSOR_ALREADY_OPEN THEN
DBMS_OUTPUT.put_line(' Exception -- CURSOR_ALREADY_OPEN');
WHEN INVALID_CURSOR THEN
DBMS_OUTPUT.put_line(' Exception -- INVALID_CURSOR');
WHEN INVALID_NUMBER THEN
DBMS_OUTPUT.put_line(' Exception -- INVALID_NUMBER');
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.put_line(' Exception -- NO_DATA_FOUND');
WHEN PROGRAM_ERROR THEN
DBMS_OUTPUT.put_line(' Exception -- PROGRAM_ERROR');
WHEN ROWTYPE_MISMATCH THEN
DBMS_OUTPUT.put_line(' Exception -- ROWTYPE_MISMATCH');
WHEN STORAGE_ERROR THEN
DBMS_OUTPUT.put_line(' Exception -- STORAGE_ERROR');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.put_line(' Exception -- TOO_MANY_ROWS');
WHEN VALUE_ERROR THEN
DBMS_OUTPUT.put_line(' Exception -- VALUE_ERROR');
END get_items_by_parent;
Inventing a print_tree based on what you describe:
procedure print_tree is
begin
get_items_by_parent(null, 0);
for i in 1..table_tree.count loop
dbms_output.put_line(to_char(table_tree(i).item_id, '99999') || ' '
|| lpad(' ', table_tree(i).spaces_number, ' ')
|| table_tree(i).item_ref);
end loop;
end print_tree;
... calling that now works, and produces 13 indented records:
1 Abraham
2 Isaac
3 Jakob
4 Yehuda
5 David
6 Solomon
7 Isaiah
8 Jeremiah
9 Josef
10 Efraim
11 Menashe
12 Benjamin
13 Ishmael
As #XING said, you can get the same result more simply with a different for of cursor loop:
procedure get_items_by_parent(p_parent in VARCHAR2, p_spaces_number in NUMBER)
AS
l_spaces_number NUMBER := 0;
CURSOR get_children_cur(p_parent in varchar2) IS
SELECT parent_item, child_item
from items_tree
where child_item is not null
and (parent_item = p_parent
or (p_parent is null and parent_item is null));
BEGIN
l_spaces_number := p_spaces_number + 3;
FOR r IN get_children_cur(p_parent)
LOOP
v_row_number := v_row_number + 1;
table_tree(v_row_number).item_id := v_row_number;
table_tree(v_row_number).spaces_number := l_spaces_number;
table_tree(v_row_number).parent_item_ref := r.parent_item;
table_tree(v_row_number).item_ref := r.child_item;
-- Calling procedure recursively
get_items_by_parent( r.child_item, l_spaces_number );
END LOOP;
END get_items_by_parent;
or even:
procedure get_items_by_parent(p_parent in VARCHAR2, p_spaces_number in NUMBER)
AS
BEGIN
FOR r IN (
SELECT parent_item, child_item
from items_tree
where child_item is not null
and (parent_item = p_parent
or (p_parent is null and parent_item is null)))
LOOP
v_row_number := v_row_number + 1;
table_tree(v_row_number).item_id := v_row_number;
table_tree(v_row_number).spaces_number := p_spaces_number + 3;
table_tree(v_row_number).parent_item_ref := r.parent_item;
table_tree(v_row_number).item_ref := r.child_item;
-- Calling procedure recursively
get_items_by_parent( r.child_item, p_spaces_number + 3 );
END LOOP;
END get_items_by_parent;
Of course, you don't need to use PL/SQL or a table at all, you can use a hierarchical query:
select rownum, lpad(' ', level * 3, ' ') || child_item as item
from items_tree
start with parent_item is null
connect by parent_item = prior child_item
order siblings by child_num;
ROWNUM ITEM
---------- --------------------------------------------------
1 Abraham
2 Isaac
3 Jakob
4 Yehuda
5 David
6 Solomon
7 Isaiah
8 Jeremiah
9 Josef
10 Efraim
11 Menashe
12 Benjamin
13 Ishmael
but presumably this is a PL/SQL exercise. If you aren't required to use a recursive procedure you could still populate your table from a similar query, using bulk collect.

Related

Unable to get dbms_sql.column_value

I'm trying to read a query from a table and process it with DBMS_SQL package. It parses correctly. I can also see the columns, which occurs in a query. But I'm not able to fetch results. In debug mode It throws the exception while trying to getting dbms_sql.column_value (please see the code below).
/*--------------------------------------------------------------------------------------------------------------------*/
PROCEDURE MY_PROC( nCSV_EXP_CFG_ID IN NUMBER,nN1 IN NUMBER DEFAULT null )
/*--------------------------------------------------------------------------------------------------------------------*/
as
l_ntt_desc_tab dbms_sql.desc_tab;
nCursorId INTEGER;
nColCnt INTEGER;
nRowCnt INTEGER;
rCSV_EXP_CFG CSV_EXP_CFG%ROWTYPE;
TYPE rowArray IS VARRAY(20) OF VARCHAR2(255);
colVal rowArray;
BEGIN
SELECT * INTO rCSV_EXP_CFG
FROM CSV_EXP_CFG
WHERE
CSV_EXP_CFG_ID = nCSV_EXP_CFG_ID;
nCursorId:=dbms_sql.open_cursor;
dbms_sql.parse(nCursorId, rCSV_EXP_CFG.EXPORT_TABLE, dbms_sql.native);
IF nN1 IS NOT NULL THEN DBMS_SQL.BIND_VARIABLE (nCursorId, 'n1', nN1); END IF;
dbms_sql.describe_columns(nCursorId, nColCnt, l_ntt_desc_tab);
FOR i IN 1..nColCnt LOOP
DBMS_OUTPUT.PUT_LINE( l_ntt_desc_tab(i).col_name);
--DBMS_SQL.DEFINE_COLUMN(nCursorId, i, colVal(i), 255);
END LOOP;
nRowCnt:=dbms_sql.execute(nCursorId);
LOOP
EXIT WHEN dbms_sql.fetch_rows(nCursorId) = 0;
FOR i IN 1..nColCnt LOOP
--here I'm getting the exception
dbms_sql.column_value(nCursorId, i, colVal(i));
END LOOP;
END LOOP;
Dbms_sql.close_cursor(nCursorId);
EXCEPTION WHEN OTHERS THEN
NULL;
END MY_PROC;
What am I doing wrong?

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!!

Cannot insert Third column of data

I am noob in PL/SQL I just start learning and I want to create small peace of software that insert data from .CVS file to Oracle database.
And I stuck in part where I grab data from .CVS file.
I my CVS there are three column: Number_Policy,Contact, Agency
Number_Policy,Contact is catch success, but Agency can not be catched and I dont know why
declare
import_file text_io.file_type;
export_file text_io.file_type;
import_file_name varchar2(1000);
export_file_name varchar2(1000);
import_log_file text_io.file_type;
import_log_file_name varchar2(1000);
vec_importovano number;
brojac number;
brojac_redova number;
linebuf varchar2(10000);
p_rbr varchar2(20);
p_polica varchar2(20);
p_banka VARCHAR2(50);
p_kontakt varchar2(20);
kraj_fajla number;
begin
brojac_redova:=0;
import_file_name := :Global.Lokacija_prenosa||:import.naziv_fajla||:Global.Ekstenzija_prenosa;
import_file := text_io.fopen(import_file_name,'r');
delete from zivot_trajni_nalog_ponude where banka is not null;
commit;
kraj_fajla := 0;
while kraj_fajla = 0 loop
begin
brojac_redova:=brojac_redova+1;
text_io.get_line(import_file, linebuf);
if brojac_redova >= 2 then
p_polica:=substr(linebuf, 1, instr(linebuf,';',1,1)-1);
-- message(p_polica);
p_kontakt:=substr(linebuf, instr(linebuf,';',1,1)+1, instr(linebuf,';',1,2) - instr(linebuf,';',1,1)-1);
p_banka:=substr(linebuf, instr(linebuf,';',1,2)+1, instr(linebuf,';',1,3) - instr(linebuf,';',1,2)-1);
-- message(p_banka);
--p_kontakt:=substr(linebuf, instr(linebuf,';',1,1)+1, instr(linebuf,';',1,2) - instr(linebuf,';',1,1)-1);
-- message(p_kontakt);
/*
p_rbr:=substr(linebuf, 1, instr(linebuf,';',1,1)-1);
-- message(p_rbr);
p_polica:=substr(linebuf, instr(linebuf,';',1,1)+1, instr(linebuf,';',1,2) - instr(linebuf,';',1,1)-1);
-- message(p_polica);
p_banka:=substr(linebuf, instr(linebuf,';',1,2)+1, instr(linebuf,';',1,3) - instr(linebuf,';',1,2)-1);
message(p_banka);
p_kontakt:=substr(linebuf, instr(linebuf,';',1,3)+1, instr(linebuf,';',1,4) - instr(linebuf,';',1,3)-1);
message(p_kontakt);
*/
if vec_importovano = 0 then
insert into ZIVOT_TRAJNI_NALOG_PONUDE
(BROJ_POLICE,BROJ_PONUDE)
values(
p_polica,
--p_rbr,
p_kontakt);
-- p_banka);
commit;
end if;
end if;
EXCEPTION WHEN NO_DATA_FOUND THEN kraj_fajla := 1;
end;
end loop;
IF p_polica IS NOT NULL
THEN
update zivot_trajni_nalog_ponude set BROJ_POLICE=rownum;
commit;
END IF;
text_io.fclose(import_file);
message ('Uspjesno zavrseno');
end;
As you can see from code there is error somewhere here
p_banka:=substr(linebuf, instr(linebuf,';',1,2)+1, instr(linebuf,';',1,3) - instr(linebuf,';',1,2)-1);
-- message(p_banka);
After I disable this column the problem is that column p_polica and p_kontakt can't be inserted into database.
If anyone know where I made mistake I would be very thankful for any help.
Looks like linebuf has only two semicolons. This piece of code worked in my short test:
if instr(linebuf,';',1,3) > 0 then
p_banka := substr(linebuf,
instr(linebuf,';',1, 2) + 1,
instr(linebuf,';',1,3) - instr(linebuf,';',1,2)-1);
else
p_banka := substr(linebuf,
instr(linebuf,';',1, 2) + 1);
end if;

Oracle: detect exception in type construtor during bulk collect

Environment: Oracle 11g
I have a type ty1 with some arguments like s1, s2.
If I use it like this:
SELECT ty1(s1,s2) BULK COLLECT INTO l_collection_of_ty1 FROM ...
I get a collection of ty1.
Now if there is an exception raised inside one of the constructor calls of ty1 the corresponding element of my collection is set to NULL, but the overall SELECT works (no exception, collection returned).
My question, can I detect this right after the SELECT without having to loop over the collection? Is there maybe even a way to access the original error message in a similar way as SQL%BULK_EXCEPTION does for DML?
One workaround I thought of is to not use the constructor during BULK COLLECT, but read collections of s1 and s2, then construct the TYPE in my own loop where I can handle the exception, but that is much more code and I would prefer it if Oracle has some build in way.
here is a testcase that demonstrates that all exceptions are thrown through a bulk-select, but NO_DATA_FOUND is dropped.
-- remember to retreive dbms_output
SET SERVEROUTPUT ON
CREATE OR REPLACE FUNCTION p1 (v1 PLS_INTEGER)
RETURN NUMBER
AS
BEGIN
CASE v1
WHEN 1
THEN
RAISE ACCESS_INTO_NULL;
WHEN 2
THEN
RAISE CASE_NOT_FOUND;
WHEN 3
THEN
RAISE COLLECTION_IS_NULL;
WHEN 4
THEN
RAISE CURSOR_ALREADY_OPEN;
WHEN 5
THEN
RAISE DUP_VAL_ON_INDEX;
WHEN 6
THEN
RAISE INVALID_CURSOR;
WHEN 7
THEN
RAISE INVALID_NUMBER;
WHEN 8
THEN
RAISE LOGIN_DENIED;
WHEN 9
THEN
RAISE NO_DATA_FOUND;
WHEN 10
THEN
RAISE NOT_LOGGED_ON;
WHEN 11
THEN
RAISE PROGRAM_ERROR;
WHEN 12
THEN
RAISE ROWTYPE_MISMATCH;
WHEN 13
THEN
RAISE SELF_IS_NULL;
WHEN 14
THEN
RAISE STORAGE_ERROR;
WHEN 15
THEN
RAISE SUBSCRIPT_BEYOND_COUNT;
WHEN 16
THEN
RAISE SUBSCRIPT_OUTSIDE_LIMIT;
WHEN 17
THEN
RAISE SYS_INVALID_ROWID;
WHEN 18
THEN
RAISE TIMEOUT_ON_RESOURCE;
WHEN 19
THEN
RAISE TOO_MANY_ROWS;
WHEN 20
THEN
RAISE VALUE_ERROR;
WHEN 21
THEN
RAISE ZERO_DIVIDE;
ELSE
RETURN v1;
END CASE;
END;
/
DECLARE
TYPE type1 IS TABLE OF NUMBER;
col1 type1;
BEGIN
FOR ii IN 1 .. 22
LOOP
BEGIN
SELECT p1 (ii)
BULK COLLECT INTO col1
FROM DUAL;
IF col1 (1) IS NULL
THEN
DBMS_OUTPUT.put_line (TO_CHAR (ii, '00') || ': NULL');
ELSE
DBMS_OUTPUT.put_line (TO_CHAR (ii, '00') || ': ' || col1 (1));
END IF;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (
TO_CHAR (ii, '00')
|| ': exception '
|| SQLCODE);
END;
END LOOP;
END;
/
I wrote a small test case for you and the exception has to be swallowed inside ty1 and not raised, because otherwise the select would not finish successfully:
create or replace function p1 (v1 number) return number
as
begin
if v1 = 1 then
return 1;
elsif v1 = 2 then
raise_application_error(-20010,'err 2');
else
raise_application_error(-20010,'err 3');
end if;
end;
/
declare
type type1 is table of number;
col1 type1;
begin
select p1(level) bulk collect into col1 from dual connect by level <=3;
end;
/
Result:
Error report -
ORA-20010: err 2
So my suggestion to you is - if you want to stay close to your solution - that at the place where you handle the exception in ty1, you write the exceptions to a table. You can then access this table to find the exceptions and don't need to loop through the whole collection. But honestly, what's wrong with looping in PL/SQL over a collection, it's all in memory? HTH
I see only two options.
An exception is consumed inside constructor.
The another constructor is in use.
Example:
create or replace type ty1 as object (p1 number
, constructor function ty1 (p1 varchar2)
return self as result);
create or replace type body ty1
is
constructor function ty1 (p1 varchar2)
return self as result is
x number;
begin
raise_application_error(-20000,'Always Exception');
return;
end;
end;
Test 1 no exception:
declare
type l_collection_of_ty1 is table of ty1;
a varchar2(4000);
x l_collection_of_ty1;
begin
--test1 select ty1(level) bulk collect into x from dual connect by level < 10;
-- no exceptions
--test2 select ty1(level||1) bulk collect into x from dual connect by level < 10;
-- exceptions
--test3 select ty1(null) bulk collect into x from dual connect by level < 10;
-- exceptions
end;
In Test1 db is using Attribute-Value Constructor. It is generate by default.
In Test2 db is using user defined constructor.
In Test3 db is not able to find out which constructor should be used.()

FORALL......SAVE EXCEPTIONS

We are using FORALL.....SAVE EXCEPTIONS. At the end of the loop, we have this:
FOR i IN 1..SQL%BULK_EXCEPTIONS.COUNT LOOP<BR><BR>
DBMS_OUTPUT.PUT_LINE('ERROR CREATING STAGING TICKER: ' || SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE));<BR><BR>
DBMS_OUTPUT.PUT_LINE('INDEX INFO: ' || SQL%BULK_EXCEPTIONS(i).ERROR_INDEX);<BR>
END LOOP;
Is there any way for me to get at actual VALUES in that array? Say if a customers email was too long.....for me to actually display the value which caused the error? Rather than just some index number?
Thanks!
You can use the loop variable i to display the content of the exception array in your case. See below an example procedure:
CREATE OR REPLACE PROCEDURE PROC1 (V_EMP_ID DBMS_SQL.NUMBER_TABLE)
IS
lv_error_string VARCHAR2(4000);
BEGIN
FORALL INDX IN V_EMP_ID.FIRST..V_EMP_ID.LAST SAVE EXCEPTIONS
UPDATE EMPLOYEES
---trying to rasie an exception by using a calculation
SET SALARY=SALARY * 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
WHERE ID_E= V_EMP_ID(INDX);
EXCEPTION
WHEN OTHERS
THEN
FOR i IN 1 .. SQL%BULK_EXCEPTIONS.COUNT
LOOP
---Am printing the value of the exception array.
dbms_output.put_line('exception Raised for record' ||V_EMP_ID(i));
END LOOP;
END;
/
Ouput:
SQL> DECLARE
empid DBMS_SQL.NUMBER_TABLE;
BEGIN
empid (1) := 1;
empid (2) := 9;
PROC1 (empid);
END;
/
exception Raised for record 1
PL/SQL procedure successfully completed.

Resources