How to append data to an output parameter which is an array? - oracle

I have a type like this ...
CREATE OR REPLACE TYPE TYPE_X
AS
TABLE OF VARCHAR2(4000);
... which is used in a package:
CREATE OR REPLACE PACKAGE PACKAGE_TEST
AS
TYPE DETAILS
IS
RECORD
(
EMPNO NUMBER,
ENAME VARCHAR2(4000),
DEPTNO NUMBER );
TYPE DETAILS_ARRAY
IS
TABLE OF DETAILS;
PROCEDURE PROC_TESTING_2(
X TYPE_X,
Y OUT DETAILS_ARRAY );
END;
CREATE OR REPLACE PACKAGE BODY PACKAGE_TEST
AS
PROCEDURE PROC_TESTING_2(
X TYPE_X,
Y OUT DETAILS_ARRAY )
AS
BEGIN
FOR I IN 1..X.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(X(I));
SELECT EMPNO,ENAME,DEPTNO INTO Y FROM EMP WHERE DEPTNO=X(I);
END LOOP;
END;
END;
I'd like to print the data into the record type by executing all the values from the TYPE_X list. The data needs to be appended till the loop exits. Appreciate your help. Thanks!!

The approach which requires the least change to your existing code would be to populate a local variable of the record type, then append that to the OUT array.
CREATE OR REPLACE PACKAGE BODY PACKAGE_TEST
AS
PROCEDURE PROC_TESTING_2(
X TYPE_X,
Y OUT DETAILS_ARRAY )
AS
l_rec DETAILS;
BEGIN
-- initialize output array
y := package_test.details_array();
FOR I IN 1..X.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(X(I));
SELECT EMPNO,ENAME,DEPTNO INTO lrec
FROM EMP
WHERE DEPTNO=X(I);
y.extend();
y(y.count) := lrec;
END LOOP;
END;
END;
This would be inefficient for a large number of rows. In that case you should look to use BULK COLLECT instead:
CREATE OR REPLACE PACKAGE BODY PACKAGE_TEST
AS
PROCEDURE PROC_TESTING_2(
X TYPE_X,
Y OUT DETAILS_ARRAY )
AS
l_rec DETAILS;
BEGIN
SELECT EMPNO,ENAME,DEPTNO
bulk collect INTO y
FROM EMP
WHERE DEPTNO in ( select * from table (X));
END;
END;

Related

Default Value for Collection in Oracle Stored Procedure

I have three tables: test_main (could be empty on start), test_sec (almost always has records) and binding table test_ref(storess unique id combinations of records from test_main and test_sec).
I need to create a package with procedures that deal with inserions and updates of records in test_main and test_ref. I need some help with it.
Here's the code of a package:
create or replace package TEST_PKG is
type t_num is table of number;
procedure ADD (arg_main_id number
, arg_name varchar2
, arg_sec_ids t_num);
end test_pkg;
create or replace package body test_pkg is
procedure ADD (arg_main_id number
, arg_name varchar2
, arg_sec_ids t_num)
is begin
insert into test_main (id, col_name)
values (arg_main_id, arg_name);
commit;
for i in arg_sec_ids.first .. arg_sec_ids.last loop
insert into test_ref (main_id, sec_id)
values (arg_main_id, arg_sec_ids(i));
end loop;
commit;
end ADD;
end test_pkg;
I plan to call this procedure in Oracle APEX 5.1 PL/SQL Dynamic Action as follows:
declare
selection apex_t_number
-- or "test_pkg.t_num" with values from "apex_string.split_numbers" added through a "for" loop later
begin
selection := apex_string.split_numbers(:P1_SELECT2,':');
-- for example, '1:2:3' string results in a [1,2,3] array
ADD (arg_main_id => :P1_MAIN_ID
, arg_name => :P1_MAIN_NAME
, arg_sec_ids => selection);
end;
But I also would like to be able to call it as ADD (arg_main_id => :P1_MAIN_ID, arg_name => :P1_MAIN_NAME) with a default value for arg_sec_ids.
So, is it possible to define default value for a collection in PL/SQL Procedure, and if so, how to?
You can define arg_sec_ids parameter as of in out style is of type t_num.
create or replace package test_pkg is
type t_num is table of number;
procedure add (
arg_main_id number,
arg_name varchar2,
arg_sec_ids in out t_num
);
end;
and suppose to initialize with arg_sec_ids := t_num(1,1,2,3,5,8); in the program body, and if you extend with an integer with value number of elements in the tuple, you can use the next values for arg_sec_ids such as arg_sec_ids(7),..,arg_sec_ids(10).
create or replace package body test_pkg is
procedure add (
arg_main_id number,
arg_name varchar2,
arg_sec_ids in out t_num
) is
begin
arg_sec_ids := t_num(1,1,2,3,5,8);
arg_sec_ids.extend(10);
insert into test_main (id, col_name)
values (arg_main_id, arg_name);
for i in arg_sec_ids.first .. arg_sec_ids.last loop
insert into test_ref (main_id, sec_id)
values (arg_main_id, arg_sec_ids(i));
end loop;
arg_sec_ids(7) := arg_sec_ids(5)+ arg_sec_ids(6);
dbms_output.put_line( ' arg_sec_ids(7)''s values is : '||arg_sec_ids(7) );
commit;
end add;
end;
If arg_sec_ids.extend(x) is omitted (where x>6 ), it's impossible to use arrays with index more than default length( which's 6 in this case ).

ORA-00902 for function that returns a table [duplicate]

I am writing a function and i want to wrap it with table function so i can use with select query.
Here is my type declaration and the some lines of my functions
CREATE OR REPLACE PACKAGE TYPES
AS
TYPE CURSORTYPE IS REF CURSOR;
TYPE vbugsrec
IS
RECORD (
bug_id bugs.bug_id%TYPE,
facility bugs.facility%TYPE
);
TYPE vbugstable
IS
TABLE OF vbugsrec
INDEX BY BINARY_INTEGER;
END;
/
CREATE OR REPLACE PACKAGE BODY CustomQueries
AS
FUNCTION pendverifylist (myldapid IN userpass.ldapalias%TYPE,
maxrows IN PLS_INTEGER:= CustomQueries.maxrecords)
RETURN types.vbugstable
IS
datarows types.vbugstable;
var_useralias userpass.ldapalias%TYPE
:= UPPER (pendverifylist.myldapid) ;
CURSOR pendverify_cur (
cursor_var_alias IN userpass.ldapalias%TYPE,
cursor_var_mybugstatus IN bugs.bug_status%TYPE,
cursor_var_wild IN qa_list.component%TYPE
)
IS
SELECT buglist.bug_id, buglist.facility
FROM bugs buglist,
(SELECT qa.product, qa.component
FROM qa_list qa, userpass UP
WHERE qa.qa_id = UP.userid
AND UP.ldapalias = cursor_var_alias) plist
WHERE buglist.bug_status = cursor_var_mybugstatus
AND buglist.smr_state IN (SELECT fs.finalstate
FROM finalstates fs)
AND buglist.facility = plist.product
AND (buglist.product LIKE plist.component
OR plist.component = cursor_var_wild);
BEGIN
OPEN pendverifylist.pendverify_cur (cursor_var_alias => pendverifylist.var_useralias,
cursor_var_mybugstatus => CustomQueries.default_bugstatus,
cursor_var_wild => CustomQueries.wildcard);
FETCH pendverifylist.pendverify_cur
BULK COLLECT INTO pendverifylist.datarows
LIMIT LEAST (GREATEST (0, pendverifylist.maxrows),
CustomQueries.MAXRECORDS);
CLOSE pendverifylist.pendverify_cur;
RETURN pendverifylist.datarows;
END pendverifylist;
END CustomQueries;
/
When i want to use TABLE function like below, i get error.ORA-00902: invalid datatype
SELECT * FROM TABLE(CUSTOMQUERIES.PENDVERIFYLIST ( 'product', 50 ));
Can anyone please help what i am doing wrong here?
Thanks in advance
You're trying to use package-level types in plain SQL, which isn't allowed. The types declared in the package are not visible to or valid outside PL/SQL (or even in plain SQL statements within PL/SQL). A cut-down version of what you're doing:
create or replace package types as
type my_rec_type is record (dummy dual.dummy%type);
type my_table_type is table of my_rec_type index by binary_integer;
end types;
/
create or replace package p42 as
function get_table return types.my_table_type;
end p42;
/
create or replace package body p42 as
function get_table return types.my_table_type is
my_table types.my_table_type;
begin
select * bulk collect into my_table from dual;
return my_table;
end get_table;
end p42;
/
select * from table(p42.get_table);
SQL Error: ORA-00902: invalid datatype
Even within the package, if you had a procedure that tried to use the table function it would error. If you added:
procedure test_proc is
begin
for r in (select * from table(get_table)) loop
null;
end loop;
end test_proc;
... the package body compilation would fail with ORA-22905: cannot access rows from a non-nested table item.
You need to declare the types at schema level, not in a package, so using the SQL create type command:
create type my_obj_type is object (dummy varchar2(1));
/
create type my_table_type is table of my_obj_type;
/
create or replace package p42 as
function get_table return my_table_type;
end p42;
/
create or replace package body p42 as
function get_table return my_table_type is
my_table my_table_type;
begin
select my_obj_type(dummy) bulk collect into my_table from dual;
return my_table;
end get_table;
end p42;
/
select * from table(p42.get_table);
DUMMY
-----
X
Actually tehere is not need to have types in schema level. All you need to do is to define function as PIPELINED.
-- DEFINITION IN PCKG HEADER
create or replace PACKAGE "AAA" IS
TYPE t_record IS RECORD (
aaa VARCHAR(20 CHAR),
bbb VARCHAR(50 CHAR),
ccc VARCHAR(10 CHAR)
);
TYPE t_collection is table of t_record;
FUNCTION get_records(p_in1 DATE, p_in2 DATE) RETURN t_collection PIPELINED;
END AAA;
-- PCKG BODY
create or replace PACKAGE BODY AAA AS
FUNCTION get_records(p_in1 DATE, p_in2 DATE) RETURN t_collection PIPELINED AS
CURSOR k1 is SELECT aaa,bbb,ccc FROM table;
BEGIN
FOR rec IN k1
LOOP
pipe row( (rec) );
END LOOP;
END get_records
END AAA;
-- CALLING FUNCTION OUTSIDE OF PCKG
select * from TABLE(AAA.get_records(par1, par2));
Thanks to Alex Poole. This is what i ended up with
CREATE OR REPLACE TYPE vbugsrec
IS
OBJECT (
bug_id NUMBER(9),
facility VARCHAR2(256)
);
CREATE OR REPLACE TYPE vbugstable
IS
TABLE OF vbugsrec;
/
CREATE OR REPLACE PACKAGE BODY CustomQueries
AS
FUNCTION pendverifylist (myldapid IN userpass.ldapalias%TYPE,
maxrows IN PLS_INTEGER:= CustomQueries.maxrecords)
RETURN vbugstable
IS
datarows vbugstable := vbugstable();
var_useralias userpass.ldapalias%TYPE:= UPPER (pendverifylist.myldapid) ;
TYPE temp_rec IS RECORD (
bug_id bugs.bug_id%TYPE,
facility bugs.facility%TYPE
);
TYPE temp_records
IS
TABLE OF temp_rec
INDEX BY BINARY_INTEGER;
temporary_records temp_records;
CURSOR pendverify_cur (
cursor_var_alias IN userpass.ldapalias%TYPE,
cursor_var_mybugstatus IN bugs.bug_status%TYPE,
cursor_var_wild IN qa_list.component%TYPE
)
IS
SELECT buglist.bug_id, buglist.facility
FROM bugs buglist,
(SELECT qa.product, qa.component
FROM qa_list qa, userpass UP
WHERE qa.qa_id = UP.userid
AND UP.ldapalias = cursor_var_alias) plist
WHERE buglist.bug_status = cursor_var_mybugstatus
AND buglist.smr_state IN (SELECT fs.finalstate
FROM finalstates fs)
AND buglist.facility = plist.product
AND (buglist.product LIKE plist.component
OR plist.component = cursor_var_wild);
BEGIN
OPEN pendverifylist.pendverify_cur (cursor_var_alias => pendverifylist.var_useralias,
cursor_var_mybugstatus => CustomQueries.default_bugstatus,
cursor_var_wild => CustomQueries.wildcard);
FETCH pendverifylist.pendverify_cur
BULK COLLECT INTO temporary_records
LIMIT LEAST (GREATEST (0, pendverifylist.maxrows),
CustomQueries.MAXRECORDS);
CLOSE pendverifylist.pendverify_cur;
IF temporary_records.COUNT <> 0
THEN
FOR rec_idx IN temporary_records.FIRST .. temporary_records.LAST
LOOP
datarows.EXTEND;
datarows (datarows.LAST) :=
vbugsrec (temporary_records (rec_idx).bug_id,
temporary_records (rec_idx).facility);
END LOOP;
END IF;
RETURN pendverifylist.datarows;
END pendverifylist;
END CustomQueries;
/

Table function with bulk collection throws invalid datatype

I am writing a function and i want to wrap it with table function so i can use with select query.
Here is my type declaration and the some lines of my functions
CREATE OR REPLACE PACKAGE TYPES
AS
TYPE CURSORTYPE IS REF CURSOR;
TYPE vbugsrec
IS
RECORD (
bug_id bugs.bug_id%TYPE,
facility bugs.facility%TYPE
);
TYPE vbugstable
IS
TABLE OF vbugsrec
INDEX BY BINARY_INTEGER;
END;
/
CREATE OR REPLACE PACKAGE BODY CustomQueries
AS
FUNCTION pendverifylist (myldapid IN userpass.ldapalias%TYPE,
maxrows IN PLS_INTEGER:= CustomQueries.maxrecords)
RETURN types.vbugstable
IS
datarows types.vbugstable;
var_useralias userpass.ldapalias%TYPE
:= UPPER (pendverifylist.myldapid) ;
CURSOR pendverify_cur (
cursor_var_alias IN userpass.ldapalias%TYPE,
cursor_var_mybugstatus IN bugs.bug_status%TYPE,
cursor_var_wild IN qa_list.component%TYPE
)
IS
SELECT buglist.bug_id, buglist.facility
FROM bugs buglist,
(SELECT qa.product, qa.component
FROM qa_list qa, userpass UP
WHERE qa.qa_id = UP.userid
AND UP.ldapalias = cursor_var_alias) plist
WHERE buglist.bug_status = cursor_var_mybugstatus
AND buglist.smr_state IN (SELECT fs.finalstate
FROM finalstates fs)
AND buglist.facility = plist.product
AND (buglist.product LIKE plist.component
OR plist.component = cursor_var_wild);
BEGIN
OPEN pendverifylist.pendverify_cur (cursor_var_alias => pendverifylist.var_useralias,
cursor_var_mybugstatus => CustomQueries.default_bugstatus,
cursor_var_wild => CustomQueries.wildcard);
FETCH pendverifylist.pendverify_cur
BULK COLLECT INTO pendverifylist.datarows
LIMIT LEAST (GREATEST (0, pendverifylist.maxrows),
CustomQueries.MAXRECORDS);
CLOSE pendverifylist.pendverify_cur;
RETURN pendverifylist.datarows;
END pendverifylist;
END CustomQueries;
/
When i want to use TABLE function like below, i get error.ORA-00902: invalid datatype
SELECT * FROM TABLE(CUSTOMQUERIES.PENDVERIFYLIST ( 'product', 50 ));
Can anyone please help what i am doing wrong here?
Thanks in advance
You're trying to use package-level types in plain SQL, which isn't allowed. The types declared in the package are not visible to or valid outside PL/SQL (or even in plain SQL statements within PL/SQL). A cut-down version of what you're doing:
create or replace package types as
type my_rec_type is record (dummy dual.dummy%type);
type my_table_type is table of my_rec_type index by binary_integer;
end types;
/
create or replace package p42 as
function get_table return types.my_table_type;
end p42;
/
create or replace package body p42 as
function get_table return types.my_table_type is
my_table types.my_table_type;
begin
select * bulk collect into my_table from dual;
return my_table;
end get_table;
end p42;
/
select * from table(p42.get_table);
SQL Error: ORA-00902: invalid datatype
Even within the package, if you had a procedure that tried to use the table function it would error. If you added:
procedure test_proc is
begin
for r in (select * from table(get_table)) loop
null;
end loop;
end test_proc;
... the package body compilation would fail with ORA-22905: cannot access rows from a non-nested table item.
You need to declare the types at schema level, not in a package, so using the SQL create type command:
create type my_obj_type is object (dummy varchar2(1));
/
create type my_table_type is table of my_obj_type;
/
create or replace package p42 as
function get_table return my_table_type;
end p42;
/
create or replace package body p42 as
function get_table return my_table_type is
my_table my_table_type;
begin
select my_obj_type(dummy) bulk collect into my_table from dual;
return my_table;
end get_table;
end p42;
/
select * from table(p42.get_table);
DUMMY
-----
X
Actually tehere is not need to have types in schema level. All you need to do is to define function as PIPELINED.
-- DEFINITION IN PCKG HEADER
create or replace PACKAGE "AAA" IS
TYPE t_record IS RECORD (
aaa VARCHAR(20 CHAR),
bbb VARCHAR(50 CHAR),
ccc VARCHAR(10 CHAR)
);
TYPE t_collection is table of t_record;
FUNCTION get_records(p_in1 DATE, p_in2 DATE) RETURN t_collection PIPELINED;
END AAA;
-- PCKG BODY
create or replace PACKAGE BODY AAA AS
FUNCTION get_records(p_in1 DATE, p_in2 DATE) RETURN t_collection PIPELINED AS
CURSOR k1 is SELECT aaa,bbb,ccc FROM table;
BEGIN
FOR rec IN k1
LOOP
pipe row( (rec) );
END LOOP;
END get_records
END AAA;
-- CALLING FUNCTION OUTSIDE OF PCKG
select * from TABLE(AAA.get_records(par1, par2));
Thanks to Alex Poole. This is what i ended up with
CREATE OR REPLACE TYPE vbugsrec
IS
OBJECT (
bug_id NUMBER(9),
facility VARCHAR2(256)
);
CREATE OR REPLACE TYPE vbugstable
IS
TABLE OF vbugsrec;
/
CREATE OR REPLACE PACKAGE BODY CustomQueries
AS
FUNCTION pendverifylist (myldapid IN userpass.ldapalias%TYPE,
maxrows IN PLS_INTEGER:= CustomQueries.maxrecords)
RETURN vbugstable
IS
datarows vbugstable := vbugstable();
var_useralias userpass.ldapalias%TYPE:= UPPER (pendverifylist.myldapid) ;
TYPE temp_rec IS RECORD (
bug_id bugs.bug_id%TYPE,
facility bugs.facility%TYPE
);
TYPE temp_records
IS
TABLE OF temp_rec
INDEX BY BINARY_INTEGER;
temporary_records temp_records;
CURSOR pendverify_cur (
cursor_var_alias IN userpass.ldapalias%TYPE,
cursor_var_mybugstatus IN bugs.bug_status%TYPE,
cursor_var_wild IN qa_list.component%TYPE
)
IS
SELECT buglist.bug_id, buglist.facility
FROM bugs buglist,
(SELECT qa.product, qa.component
FROM qa_list qa, userpass UP
WHERE qa.qa_id = UP.userid
AND UP.ldapalias = cursor_var_alias) plist
WHERE buglist.bug_status = cursor_var_mybugstatus
AND buglist.smr_state IN (SELECT fs.finalstate
FROM finalstates fs)
AND buglist.facility = plist.product
AND (buglist.product LIKE plist.component
OR plist.component = cursor_var_wild);
BEGIN
OPEN pendverifylist.pendverify_cur (cursor_var_alias => pendverifylist.var_useralias,
cursor_var_mybugstatus => CustomQueries.default_bugstatus,
cursor_var_wild => CustomQueries.wildcard);
FETCH pendverifylist.pendverify_cur
BULK COLLECT INTO temporary_records
LIMIT LEAST (GREATEST (0, pendverifylist.maxrows),
CustomQueries.MAXRECORDS);
CLOSE pendverifylist.pendverify_cur;
IF temporary_records.COUNT <> 0
THEN
FOR rec_idx IN temporary_records.FIRST .. temporary_records.LAST
LOOP
datarows.EXTEND;
datarows (datarows.LAST) :=
vbugsrec (temporary_records (rec_idx).bug_id,
temporary_records (rec_idx).facility);
END LOOP;
END IF;
RETURN pendverifylist.datarows;
END pendverifylist;
END CustomQueries;
/

How can I return multiple values in record type

I'd like to know how can I return multiple values with my PL/SQL in record type.
Below is my example code :-
CREATE OR REPLACE FUNCTION "FN_TESTING"
(
TESTING1 IN VARCHAR2
) RETURN TEST4_TEST as
TEST2 TEST4_TEST%ROWTYPE;
CURSOR TEST1 IS
SELECT '1','2' FROM DUAL;
BEGIN
OPEN TEST1;
FETCH TEST1
INTO TEST2;
CLOSE TEST1;
RETURN TEST2;
END FN_TESTING;
I do check my function, it shows me warning message that my TEST4_TEST must be declared.
Can I know what is the problem of this function? and how I do the declaration for this TEST4_TEST?
Yes we can return the record variable from PLSQL Function/Procedure. But first it must be declare.
create or replace function get_employee
(p_empl_no in employee.empl_no%type)
return employee%rowtype
as
l_cust_record employee%rowtype;
begin
select * into l_cust_record from employee
where empl_no = p_empl_no;
return(l_cust_record);
end;
/
Think TEST4_TEST as a variable which is of TYPE Record. This variable is just like NUMBER, VARCHAR, DATE. Only difference being that these are already defined by Oracle but in case of Collections and Records we have to define our own.
As per your example it seems that you want to return a record with 2 numbers values then you should define as follow
CREATE OR REPLACE PACKAGE TEST4_TEST1
AS
TYPE TEST4_TEST Is record
(
COL1 INTEGER,
COL2 INTEGER
);
END;
CREATE OR REPLACE FUNCTION FN_TESTING (testing1 IN VARCHAR2)
RETURN TEST4_TEST1.test4_test
AS
test3 TEST4_TEST1.test4_test;
CURSOR test2
IS
SELECT '1', '2' FROM DUAL;
A
BEGIN
OPEN test2;
FETCH test2 INTO test3;
CLOSE test2;
RETURN test3;
END fn_testing;
Try this also:
declare TYPE t_deptrec IS RECORD
(
name dept.dname%type,
location dept.loc%type
);
CURSOR c_emp is
select ename,deptno from emp;
r_dept t_deptrec;
function getDept(p_deptno dept.deptno%type) return t_deptrec is
r_dept t_deptrec;
begin
select dname,loc into r_dept
from dept where deptno = p_deptno;
return r_dept;
end;
BEGIN
for r_emp in c_emp
loop
r_dept := getDept(r_emp.deptno);
dbms_output.put_line(r_emp.ename || ',' || r_dept.name || ',' || r_dept.location);
end loop;
END;

How to use function returning Oracle REF_CURSOR in a procedure

I have to write an Oracle procedure which should invoke an Oracle function returning REF_CURSOR. The function is declared like that
FUNCTION "IMPACTNET"."TF_CONVERTPARA" (PARASTRING IN NVARCHAR2) RETURN SYS_REFCURSOR
AS
c SYS_REFCURSOR;
BEGIN
OPEN c FOR
SELECT SUBSTR(element, 1, INSTR(element, '|') - 1) as key,
SUBSTR(element, INSTR(element, '|') + 1, 99999) as val
FROM (
SELECT REGEXP_SUBSTR(PARASTRING, '[^;]+', 1, LEVEL) element
FROM dual
CONNECT BY LEVEL < LENGTH(REGEXP_REPLACE(PARASTRING, '[^;]+')) + 1
);
RETURN c;
END;
Can you tell me what I need to write in order to invoke the function from within my procedure? I'd like to insert all the returned values (shaped a table with two columns) into a rational table.
Thank you in advance!
Something along the lines of this should work (obviously, I'm guessing about table names and column names and the exact logic that you're trying to implement)
CREATE PROCEDURE some_procedure_name
AS
l_rc SYS_REFCURSOR := impactnet.tf_convertpara( <<some string>> );
l_key VARCHAR2(100);
l_val VARCHAR2(100);
BEGIN
LOOP
FETCH l_rc
INTO l_key, l_val;
EXIT WHEN l_rc%notfound;
INSERT INTO some_table( key_column, val_column )
VALUES( l_key, l_val );
END LOOP;
END;
As Ollie points out, it would be more efficient to do a BULK COLLECT and a FORALL. If you're just dealing with a few thousand rows (since your function is just parsing the data in a delimited string, I'm assuming you expect relatively few rows to be returned), the performance difference is probably minimal. But if you're processing more data, the difference can be quite noticeable. Depending on the Oracle version and your specific requirements, you may be able to simplify the INSERT statement in the FORALL to insert a record rather than listing each column from the record individually.
CREATE PROCEDURE some_procedure_name
AS
TYPE key_val_rec
IS RECORD(
key VARCHAR2(100),
val VARCHAR2(100)
);
TYPE key_val_coll
IS TABLE OF key_val_rec;
l_rc SYS_REFCURSOR := impactnet.tf_convertpara( <<some string>> );
l_coll key_val_coll;
BEGIN
LOOP
FETCH l_rc
BULK COLLECT INTO l_coll
LIMIT 100;
EXIT WHEN l_coll.count = 0;
FORALL i IN l_coll.FIRST .. l_coll.LAST
INSERT INTO some_table( key_column, val_column )
VALUES( l_coll(i).key, l_coll(i).val );
END LOOP;
END;

Resources