Item Query From Table and Send It To Procedure - oracle

Note
I want to query page item name and send the corresponding items value into a procedure. I can get the item name but couldn't get the value of it. At first I use the following code:
begin
for j in (select item_name from UTLITMINF where service_id ='abc' ) loop
val := val || ':' || j.item_name; --items name
END LOOP;
/* exe := ' begin
dynamic_api_call(p_service => :ser,
p_par => :v_val, --items value to need to send
o_result_json => :v_l_response_text);
end; ';
execute immediate exe
using IN ser,
in val,
out l_response_text;*/
begin
dynamic_api_call(p_service => 'abc',
p_par => val, --items name from page queried from table and send its value to procedure
o_result_json => l_response_text);
end;
raise_application_error(-20001,l_response_text);
end;
In val parameter it contains P11_CUSTOMER. But the value of it did not pass through the procedure. How can I get the value of it? Suggest me if i need to improve my code.

You can use the V (short for value) and NV (short for numeric value) function for dynamic item names. Try something like this (you'll need to adjust on your end).
declare
l_response_text varchar2(255);
l_ser varchar2(255) := 'abc';
l_item_name varchar2(255);
begin
select item_name
into l_item_name
from UTLITMINF
where service_id = l_ser;
dynamic_api_call(
p_service => l_ser,
p_par => v(l_item_name),
o_result_json => l_response_text
);
end;

Try the dynamic sql like the below
begin
for j in (select item_name from UTLITMINF where service_id ='abc' ) loop
val := val || ':' || j.item_name; --items name
END LOOP;
exe := ' begin
dynamic_api_call(p_service => :ser,
p_par => :v_val, --items value to need to send
o_result_json => :v_l_response_text);
end ;';
execute immediate exe
using ser,
val,
OUT l_response_text;
raise_application_error(-20001,l_response_text);

Related

How to modify a CLOB line containing a certain value by using a trigger with PLSQL?

I am struggling with an issue regarding a CLOB.
I would like to create a trigger (after update) which updates the column of a table which is a CLOB.
This CLOB contains lines in this form :
foo|132|65|12/08/2016|18395|
bar|132|54|15/08/2014|32434343|
I would like to modify the CLOB such that the line beginning with "foo" has the value "18395" divided by 1000. The line will look like
foo|132|65|12/08/2016|18.395|
Is there a quick way to modify my CLOB?
Thank you for your help.
EDIT : I found a way to modify the line of the CLOB what I need to do is just to modify the CLOB to replace
foo|132|65|12/08/2016|18395|
by
foo|132|65|12/08/2016|18.395|
This is rather long but effective.
Firstly create a type:
create or replace TYPE "array_str" AS VARRAY(10) OF VARCHAR(256);
Then create a function that will return a array based in a delimiter:
FUNCTION string_to_array (
string_delimited IN VARCHAR2,
delimiter IN VARCHAR2 DEFAULT ','
) RETURN array_str IS
pls_idx PLS_INTEGER;
split_string array_str := array_str();
pls_del_len PLS_INTEGER := length(delimiter);
BEGIN
IF string_delimited IS NOT NULL THEN
LOOP
-- search for delimiter string
pls_idx := instr(l_string_delimited, delimiter);
-- increase the size of array
split_string.extend;
-- check last search of delimiter is success
IF pls_idx = 0 THEN
split_string(l_split_string.count) := substr(l_string_delimited, 1);
ELSE
split_string(l_split_string.count) := substr(l_string_delimited, 1, pls_idx - 1);
END IF;
-- exit from loop when last string
EXIT WHEN nvl(l_pls_idx, 0) = 0;
string_delimited := substr(l_string_delimited, pls_idx + pls_del_len);
END LOOP;
END IF;
RETURN split_string;
END string_to_array;
Then create your trigger:
CREATE OR REPLACE TRIGGER your_trigger AFTER
UPDATE ON table_name
FOR EACH ROW
DECLARE
clob_array array_str;
clob_str CLOB := '';
BEGIN
clob_array := string_to_array(:new.new_clob, '|');
IF ( clob_array(1) = 'foo' ) THEN
clob_array(5) := to_number(clob_array(5) / 1000);
END IF;
FOR i IN 1..clob_array.count - 1 LOOP clob_str := clob_str
|| to_char(clob_array(i))
|| '|';
END LOOP;
-- do something with clob_str
END;

Accessing elements of Oracle PLSQL record type on runtime

I am using dynamic SQL where I am dynamically using value of column name to bind and its value to be bind
OLD CODE
<Outer Loop>
FOR i IN lvaDBOBJDTLRecTab.FIRST .. lvaDBOBJDTLRecTab.LAST
LOOP
DBMS_SQL.BIND_VARIABLE ( lvnInsertCursorId, ':RTTEXT2VC100',
lvaDBOBJDTLRecTab(i).DBONAME );
DBMS_SQL.BIND_VARIABLE ( lvnInsertCursorId, ':RTTEXT3VC100',
lvaDBOBJDTLRecTab(i).DBOTYPE );
3.
.
.
.
100
END LOOP;
Instead of writing BIND_VARIABLE for 100 times , I want to dynamically access value of collection. I am able to fetch the value of columns dynamically, which need to be bind (lvsColForBinding), however value of lvsColValForBind
is coming as 'lvrCurDBOBJDTL(i).DBONAME' , 'lvrCurDBOBJDTL(i).DBOTYPE'
and same for rest of the 98 columns,
<Inner Loop>
FOR j IN lvaMappingTab.FIRST..lvaMappingTab.LAST
LOOP
lvsColForBinding := ':'||lvaMappingTab(j).MstRptColCds;
lvsColValForBind := 'lvrCurDBOBJDTL(i).'||lvaMappingTab(j).RptColCd;
DBMS_SQL.BIND_VARIABLE ( lvnInsertCursorId,lvsColForBinding, lvsColValForBind);
END LOOP;
when DBMS_SQL.BIND_VARIABLE is run for each row, as mentioned earlier Column to be bind comes correct but value to be bind, instead of coming as
value of 'XYZ' = lvrCurDBOBJDTL(i).DBONAME it comes as this in single quotes 'lvrCurDBOBJDTL(i).DBONAME' same for all columns.
how can we extract the value of each element in inner loop. what step we need to do to fetch the value of lvsColValForBind?
While debugging through SQLDEveloper Watches, I can see the, element name, value and type, when adding and double clicking the plsql record variable,
what is the SQL behind that, can we use that in coding ?
My first recommendation is that you use dynamic SQL to generate lots of dumb code instead of using a small amount of smart PL/SQL. If code generation doesn't work, you can use ANYDATA and ANYTYPE to create PL/SQL reflection to dynamically iterate through the elements of a record at run time.
Code Generation
Don't write BIND_VARIABLE 100 times, but create a small program to generate the 100 lines of code for you. If the data is ultimately coming from one table and going into another table, the input and output may be predictable based on data dictionary views like DBA_TAB_COLUMNS.
Hopefully a small query like this could help generate all the code for a single table:
--Generate PL/SQL statements for binds.
select
'DBMS_SQL.BIND_VARIABLE(lvnInsertCursorId, '':RTTEXT'||column_id||'VC100'', lvaDBOBJDTLRecTab(i).'||column_name||');'
from dba_tab_columns
where owner = 'SOME_OWNER'
and table_name = 'SOME_TABLE'
order by 1;
Then you can copy-and-paste the output into the PL/SQL block. You'll probably also want a warning, like "do not modify, this code is autogenerated by the procedure CODE_TRON_2000".
This approach will only work if the PL/SQL code is predictable, based on the data dictionary or some other metadata.
PL/SQL Reflection
There's no pure PL/SQL reflection for PL/SQL types* but there's a simple workaround if you're willing to create the record types as SQL objects instead. If all your PL/SQL records are based on object types then ANYDATA and ANYTYPE can be used to dynamically access attributes. Object types and PL/SQL record types are pretty similar, it should be relatively painless to convert one to the other.
For example, if you create an object type that contains a number and a string:
create or replace type v_type is object(a number, b varchar2(1));
This (painful) PL/SQL block shows how to iterate through all the records of a collection, and then iterate through all of the attributes in each record. (The code prints the values for, you'll have to add the binding parts yourself.)
declare
type v_nt_type is table of v_type;
v_values v_nt_type := v_nt_type(v_type(1, 'A'), v_type(2, 'B'));
begin
--For each record:
for i in 1 .. v_values.count loop
declare
v_anydata anydata := anydata.ConvertObject(v_values(i));
v_number number;
v_varchar2 varchar2(4000);
v_result pls_integer;
v_anytype anytype;
v_dummy_num pls_integer;
v_dummy_char varchar2(4000);
v_dummy_anytype anytype;
v_number_of_elements number;
begin
--Get the ANYTYPE and the number of elements.
v_result := v_anydata.getType(v_anytype);
v_result := v_anytype.getInfo
(
prec => v_dummy_num,
scale => v_dummy_num,
len => v_dummy_num,
csid => v_dummy_num,
csfrm => v_dummy_num,
schema_name => v_dummy_char,
type_name => v_dummy_char,
version => v_dummy_char,
numelems => v_number_of_elements
);
--For each element in the record:
for i in 1 .. v_number_of_elements loop
--Find the type of the element:
v_anydata.piecewise;
v_result := v_anytype.getAttrElemInfo(
pos => i,
prec => v_dummy_num,
scale => v_dummy_num,
len => v_dummy_num,
csid => v_dummy_num,
csfrm => v_dummy_num,
attr_elt_type => v_dummy_anytype,
aname => v_dummy_char);
--This is where you do something interesting with the values.
--(The same code merely prints the values.)
if v_result = dbms_types.typecode_number then
v_result := v_anydata.getNumber(num => v_number);
dbms_output.put_line(v_number);
elsif v_result = dbms_types.typecode_varchar2 then
v_result := v_anydata.getVarchar2(c => v_varchar2);
dbms_output.put_line(v_varchar2);
--TODO: Add other potential types here.
end if;
end loop;
end;
end loop;
end;
/
Results:
1
A
2
B
* You're right that there must be some way to find this run time information, if the debugger gets it. But as far as I know there is no way for PL/SQL to retrieve that debug information. Maybe it's only available to an OCI(?) interface?
When you call bind_variable, you are binding an actual value to a placeholder. So if you provide a string that is the name of your variable, well, that string is the value bound to the placeholder.
If the array holds those values, then simply reference the array element and not the name of that element, as in:
DBMS_SQL.BIND_VARIABLE (
lvnInsertCursorId,
lvaMappingTab(j).MstRptColCds,
lvrCurDBOBJDTL(i).lvaMappingTab(j).RptColCd);
But I am pretty sure that's not what you've got there. Hope this helps!
#Jon
Thanks for your inputs, that helped. also I am able to iterate cols without creating OBJECTs using DBMS_SQL.DESCRIBE_COLUMNS.
**Below code still need little bit fine tuning, but mostly working :)
BEGIN
COLS_TRAVERSE('SELECT * FROM ALL_OBJECTS WHERE ROWNUM<=100');
END;
create or replace PROCEDURE COLS_TRAVERSE ( p_query in varchar2 )
AS
v_curid NUMBER;
v_desctab DBMS_SQL.DESC_TAB;
v_colcnt NUMBER;
v_RowNumcnt NUMBER := 1;
v_Colname_var VARCHAR2(10000);
v_name_var VARCHAR2(10000);
v_num_var NUMBER;
v_date_var DATE;
v_row_num NUMBER;
p_sql_stmt VARCHAR2(1000);
BEGIN
v_curid := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(v_curid, p_query, DBMS_SQL.NATIVE);
DBMS_SQL.DESCRIBE_COLUMNS(v_curid, v_colcnt, v_desctab);
-- Define columns:
FOR i IN 1 .. v_colcnt LOOP
IF v_desctab(i).col_type = 2 THEN
DBMS_SQL.DEFINE_COLUMN(v_curid, i, v_num_var);
ELSIF v_desctab(i).col_type = 12 THEN
DBMS_SQL.DEFINE_COLUMN(v_curid, i, v_date_var);
ELSE
DBMS_SQL.DEFINE_COLUMN(v_curid, i, v_name_var, 50);
END IF;
END LOOP;
v_row_num := dbms_sql.execute(v_curid);
-- Fetch rows with DBMS_SQL package:
WHILE DBMS_SQL.FETCH_ROWS(v_curid) > 0 LOOP
FOR i IN 1 .. v_colcnt
LOOP
v_Colname_var := v_desctab(i).col_name;
dbms_output.put_line( 'Name:' ||v_Colname_var );
IF (v_desctab(i).col_type = 1) THEN
DBMS_SQL.COLUMN_VALUE(v_curid, i, v_name_var);
dbms_output.put_line( 'String Value:' || v_name_var );
ELSIF (v_desctab(i).col_type = 2) THEN
DBMS_SQL.COLUMN_VALUE(v_curid, i, v_num_var);
dbms_output.put_line( 'Number Value:' || v_num_var);
ELSIF (v_desctab(i).col_type = 12) THEN
DBMS_SQL.COLUMN_VALUE(v_curid, i, v_date_var);
dbms_output.put_line( 'Date Value:' || v_date_var );
END IF;
END LOOP;
dbms_output.put_line( 'End of Row Number # ' ||v_RowNumcnt );
v_RowNumcnt := v_RowNumcnt+1;
END LOOP;
DBMS_SQL.CLOSE_CURSOR(v_curid);
END;
/
DBMS_OUT PUT
Name:OWNER
String Value:SYS
Name:OBJECT_NAME
String Value:ORA$BASE
Name:SUBOBJECT_NAME
String Value:
Name:OBJECT_ID
Number Value:134
Name:DATA_OBJECT_ID
Number Value:
Name:OBJECT_TYPE
String Value:EDITION
Name:CREATED
Date Value:30-03-18
Name:LAST_DDL_TIME
Date Value:30-03-18
Name:TIMESTAMP
String Value:2018-03-30:21:37:22
Name:STATUS
String Value:VALID
Name:TEMPORARY
String Value:N
Name:GENERATED
String Value:N
Name:SECONDARY
String Value:N
Name:NAMESPACE
Number Value:64
Name:EDITION_NAME
String Value:
Name:SHARING
String Value:NONE
Name:EDITIONABLE
String Value:
Name:ORACLE_MAINTAINED
String Value:Y
Name:APPLICATION
String Value:N
Name:DEFAULT_COLLATION
String Value:
Name:DUPLICATED
String Value:N
Name:SHARDED
String Value:N
Name:CREATED_APPID
Number Value:
Name:CREATED_VSNID
Number Value:
Name:MODIFIED_APPID
Number Value:
Name:MODIFIED_VSNID
Number Value:
End of Row Number # 1
Name:OWNER
String Value:SYS
Name:OBJECT_NAME
String Value:DUAL
Name:SUBOBJECT_NAME
String Value:
Name:OBJECT_ID
Number Value:143
Name:DATA_OBJECT_ID
Number Value:143
Name:OBJECT_TYPE
String Value:TABLE
Name:CREATED
Date Value:30-03-18
Name:LAST_DDL_TIME
Date Value:31-03-18
Name:TIMESTAMP
String Value:2018-03-30:21:37:22
Name:STATUS
String Value:VALID
Name:TEMPORARY
String Value:N
Name:GENERATED
String Value:N
Name:SECONDARY
String Value:N
Name:NAMESPACE
Number Value:1
Name:EDITION_NAME
String Value:
Name:SHARING
String Value:METADATA LINK
Name:EDITIONABLE
String Value:
Name:ORACLE_MAINTAINED
String Value:Y
Name:APPLICATION
String Value:N
Name:DEFAULT_COLLATION
String Value:USING_NLS_COMP
Name:DUPLICATED
String Value:N
Name:SHARDED
String Value:N
Name:CREATED_APPID
Number Value:
Name:CREATED_VSNID
Number Value:
Name:MODIFIED_APPID
Number Value:
Name:MODIFIED_VSNID
Number Value:
End of Row Number # 2

Find source na replacement parameters in a string and perform replacement in another string

I need a function that applies a certain rule to replace words in a string.
There are two variables:
v_imp_user_list - list of users delimited by pipe (example: JOHN|PETER|MARK|USER_PROD)
v_schema_remap_list - list of users that should be remapped (old value - new value, example: JOHN-GEORGE,USER_PROD-USER_TEST)
The function should parse v_schema_remap_list variable and if the name of the first user (before dash, old value)
exist in v_imp_user_list then replace it with the second user (after dash, new value).
Example:
v_imp_user_list := 'JOHN|PETER|MARK|USER_PROD'
v_schema_remap_list := 'JOHN-GEORGE,USER_PROD-USER_TEST'
Desired outcome:
GEORGE|PETER|MARK|USER_TEST
I have a solution which I will post but for some reason I don't like it and will appreciate any comment/review/better solution.
This function helps me to parse the v_schema_remap_list.
-- extract nth occurence in a delimited string
create or replace function f_find_str (
source_string varchar2
, occurence_outer number --occurence of the old-new pair
, occurence_inner number --old/new value, enter 1 for old or 2 for new
)
return varchar2
is
v_aux varchar2(500);
v_result varchar2(100);
begin
v_aux := ltrim(regexp_substr(',' || source_string, ',[^,]*', 1, occurence_outer),',');
if occurence_inner = 1 then
v_result := substr(v_aux, 1, instr(v_aux, '-')-1);
elsif occurence_inner = 2 then
v_result := substr(v_aux, instr(v_aux, '-')+1);
end if;
return v_result;
end;
/
This anonymous block shows my solution (see the loop inside).
declare
v_schema_remap_list varchar2(1000) := 'JOHN-GEORGE,USER_PROD-USER_TEST';
v_imp_user_list varchar2(1000) := 'JOHN|PETER|MARK|USER_PROD';
v_schema_remap_cnt number := nvl(regexp_count(v_schema_remap_list, '-'), 0);
begin
for i in 1..v_schema_remap_cnt
loop
v_imp_user_list := replace(
v_imp_user_list||'|',
f_find_str (
source_string => v_schema_remap_list
, occurence_outer => i
, occurence_inner => 1
)||'|',
f_find_str (
source_string => v_schema_remap_list
, occurence_outer => i
, occurence_inner => 2
)||'|'
);
v_imp_user_list := rtrim(v_imp_user_list, '|');
end loop;
dbms_output.put_line(v_imp_user_list); --test output
end;
/

Calling an internal function inside a procedure PL/SQL

A bit green with PL/SQL functions but trying to add a function where if the current person does not have an alt_id to get the relative alt_id via the application. Many thanks in advance.
CREATE OR REPLACE PROCEDURE CLIENT.p_Verification(pin_Member_ID IN dbo.member.member_id%Type,
pin_Person_ID IN dbo.person.person_id%type,
pin_user_id IN NUMBER default null,
pioc_ref_cursor IN OUT dbo.pkg_benefit_q.ref_cursor) IS
lv_member_id dbo.person.alt_identifier%Type;
-- other variables
...
Procedure p_get_other_deductions(...
Begin
...
end;
new function here
FUNCTION f_get_alt_id
RETURN Varchar2
IS-- dbo.person.alt_identifier%Type IS
alt_id Varchar2(10); --dbo.person.alt_identifier%Type;
BEGIN
SELECT p.ALT_IDENTIFIER
into alt_id
FROM DBO.PERSON p , DBO.MEMBER m, DBO.APPLICATION a
where p.PERSON_ID = m.PERSON_ID
AND m.MEMBER_ID = a.MEMBER_ID
AND a.APPLICATION_ID= cn_EntAppId
;
RETURN alt_id;
END;
calling it here...
Select dbo.pkg_benefit_s.f_get_value_description('PREFIX',
p.prefix,
'Y',
'N') || case
when p.prefix is not null then
' '
else
Null
end || nvl2(p.first_name, initcap(p.first_name) || ' ', '') ||
nvl2(p.middle_name, initcap(p.middle_name) || ' ', '') ||
nvl2(p.last_name, initcap(p.last_name), '') || ' ' ||
dbo.pkg_benefit_s.f_get_value_description('SUFFIX',
p.suffix,
'Y',
'N'),
nvl2(p.alt_identifier,
f_get_alt_id, -- errors here
''),
nvl2(p.first_name, initcap(p.first_name), ''),
nvl2(p.last_name, initcap(p.last_name), '')
into lv_member_name,
lv_member_id,
lv_member_first_name,
lv_member_last_name
From dbo.person p
where p.person_id = ln_person_id;
... more code
END p_Verification;
/
It would be better practice in a number of ways to create a package that has your procedure and your function listed in the header and the body.
CREATE OR REPLACE PACKAGE CLIENT IS
PROCEDURE p_Verification(pin_Member_ID IN dbo.member.member_id%Type,
pin_Person_ID IN dbo.person.person_id%type,
pin_user_id IN NUMBER default null,
pioc_ref_cursor IN OUT dbo.pkg_benefit_q.ref_cursor);
Procedure p_get_other_deductions(...
FUNCTION f_get_alt_id(alt_id_in IN NUMBER:= NULL) RETURN Varchar2;
END CLIENT;
CREATE OR REPLACE PACKAGE BODY CLIENT IS
END CLIENT;
Notice how I have added a null parameter so if you need to redesign the function you can do so without invalidating any dependent objects.
I added the
alt_id varchar(10) in the declaration section
restored the select query above to simply return
dbo.pkg_benefit_s.f_get_value_description('SUFFIX',
p.suffix,
'Y',
'N'),
p.alt_identifier,
nvl2(p.first_name, initcap(p.first_name), ''),
nvl2(p.last_name, initcap(p.last_name), '')
into lv_member_name,
lv_member_id,
lv_member_first_name,
lv_member_last_name
... everything else is the same...until
I added another section to set the lv_member_id
BEGIN
Select p.alt_identifier
into alt_id
from dbo.person p
where P.PERSON_ID = pin_Person_id;
if alt_id is not null
then
lv_member_id := alt_id;
else
lv_member_id := f_get_alt_id;
end if;
END;
... rest of procedure and end; -- it now compiles

How to run this stored procedure

I have to check this procedure
im giving following values as parameters
34220, 2815,'7/20/2011', 32760, 100, 'PMNT_CHECK', 1, null, "", false, null, null
DECLARE
P_APP_ID NUMBER;
P_USER_ID NUMBER;
P_DATE DATE;
P_INV_IDS WB_PROD.WB_PCK_TYPES.T_IDS;
P_AMNTS WB_PROD.WB_PCK_TYPES.T_NUMBERS;
P_PMNT_METHOD VARCHAR2(15);
P_BANK_AC_FROM NUMBER;
P_CHECK_NUMBERS WB_PROD.WB_PCK_TYPES.T_NUMBERS;
P_MEMO VARCHAR2(1000);
P_PAY_MULTIPLE NUMBER;
P_CRD_IDS WB_PROD.WB_PCK_TYPES.T_IDS;
P_CRD_AMOUNTS WB_PROD.WB_PCK_TYPES.T_PRICES;
O_PY_ID NUMBER;
BEGIN
P_APP_ID := 34220;
P_USER_ID := 2815;
P_DATE := '7/20/2011';
-- Modify the code to initialize the variable
P_INV_IDS := 32760;
-- Modify the code to initialize the variable
P_AMNTS := 100;
P_PMNT_METHOD := 'PMNT_CHECK';
P_BANK_AC_FROM := 1;
-- Modify the code to initialize the variable
--P_CHECK_NUMBERS := NULL;
P_MEMO := '';
P_PAY_MULTIPLE := false;
-- Modify the code to initialize the variable
-- P_CRD_IDS := NULL;
-- Modify the code to initialize the variable
-- P_CRD_AMOUNTS := NULL;
WB_PCK_BILL_PAYMENTS.PAY_BILLS(
P_APP_ID => P_APP_ID,
P_USER_ID => P_USER_ID,
P_DATE => P_DATE,
P_INV_IDS => P_INV_IDS,
P_AMNTS => P_AMNTS,
P_PMNT_METHOD => P_PMNT_METHOD,
P_BANK_AC_FROM => P_BANK_AC_FROM,
P_CHECK_NUMBERS => P_CHECK_NUMBERS,
P_MEMO => P_MEMO,
P_PAY_MULTIPLE => P_PAY_MULTIPLE,
P_CRD_IDS => P_CRD_IDS,
P_CRD_AMOUNTS => P_CRD_AMOUNTS,
O_PY_ID => O_PY_ID
);
DBMS_OUTPUT.PUT_LINE('O_PY_ID = ' || O_PY_ID);
END;
Im getting error at this line
P_INV_IDS := 32760;
i checked type of
P_INV_IDS WB_PROD.WB_PCK_TYPES.T_IDS;
which is in Declare statement, which is like this
type t_ids is table of t_id
index by binary_integer;
I donot understand how to give parameter to this type. Please let me know how to give this parameter.
Thank you
P_INV_IDS is an associative array as per your type declaration.
you can not assign this way
P_INV_IDS := 32760;
you need to specify the index in P_INV_IDS to which you are assigning value
something like
P_INV_IDS(0) := 32760;
P_INV_IDS(1) := 32761;
http://www.java2s.com/Tutorial/Oracle/0520__Collections/AssignvaluetoPLSQLtable.htm
How is the TYPE t_id defined? That will dictate how you initialize this array. If it were a number, then you will want to initialize your value this way:
P_INV_IDS(1) := 32760;
If, however, t_id is defined as, say a RECORD:
TYPE t_id IS RECORD (
ID INTEGER;
DESCRIPTION VARCHAR2(32);
);
Then you might want to initialize thusly:
P_INV_IDS(1).id := 32760;
P_INV_IDS(1).description := 'Description for 32760';

Resources