I want to pass an integer array to a stored procedure via c#. the procedure works via sql developer but in c# it doesn\'t work. this is my code but i got stuck by the
Your type:
create or replace TYPE INNUMARRAY AS TABLE OF INTEGER;
is a collection defined in the SQL scope.
Your passed argument:
p_strings.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
p_strings.Value = new int[5]{1,2,3,4,5};
is an associative array which can only be defined in a PL/SQL scope (i.e. in a package or within a PL/SQL block) and cannot be used in an SQL scope.
They are two different and incompatible data types.
Instead, you can create an associative array type in a package and then manually extract each value from the associative array into a collection that can be used in the SQL scope:
CREATE PACKAGE vehicles_pkg IS
TYPE INNUMASSOCARRAY IS TABLE OF INTEGER INDEX BY BINARY_INTEGER;
PROCEDURE v1
(
VehicleGroupID_Array IN INNUMASSOCARRAY
);
END;
/
CREATE PACKAGE BODY vehicles_pkg IS
PROCEDURE v1
(
VehicleGroupID_Array IN INNUMASSOCARRAY
)
IS
p_recordset SYS_REFCURSOR;
p_array INNUMARRAY := INNUMARRAY();
i BINARY_INTEGER;
BEGIN
i := VehicleGroupID_Array.FIRST;
WHILE i IS NOT NULL LOOP
p_array.EXTEND;
p_array( p_array.COUNT ) := VehicleGroupID_Array(i);
i := VehicleGroupID_Array.NEXT(i);
END LOOP;
-- Rest of your procedure using p_array instead of the associative array.
END;
END;
/
can I define the associative array type outside of package? I want them to be standalone.
No, but you can define a package just containing the type:
CREATE PACKAGE vehicles_pkg IS
TYPE INNUMASSOCARRAY IS TABLE OF INTEGER INDEX BY BINARY_INTEGER;
END;
/
CREATE PROCEDURE v1
(
VehicleGroupID_Array IN vehicles_pkg.INNUMASSOCARRAY
)
IS
p_recordset SYS_REFCURSOR;
p_array INNUMARRAY := INNUMARRAY();
i BINARY_INTEGER;
BEGIN
i := VehicleGroupID_Array.FIRST;
WHILE i IS NOT NULL LOOP
p_array.EXTEND;
p_array( p_array.COUNT ) := VehicleGroupID_Array(i);
i := VehicleGroupID_Array.NEXT(i);
END LOOP;
-- Rest of your procedure using p_array instead of the associative array.
END;
/
Or, better, create some generically named types and a function in the package to translate from an associative array to a collection and then reuse them in your procedures:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TYPE IntList AS TABLE OF INTEGER
/
CREATE PACKAGE tools IS
TYPE IntMap IS TABLE OF INTEGER INDEX BY BINARY_INTEGER;
FUNCTION IntMapToList(
i_map IntMap
) RETURN IntList;
END;
/
CREATE PACKAGE BODY tools IS
FUNCTION IntMapToList(
i_map IntMap
) RETURN IntList
IS
o_list IntList := IntList();
i BINARY_INTEGER;
BEGIN
IF i_map IS NOT NULL THEN
i := o_list.FIRST;
WHILE i IS NOT NULL LOOP
o_list.EXTEND;
o_list( o_list.COUNT ) := i_map( i );
i := i_map.NEXT( i );
END LOOP;
END IF;
RETURN o_list;
END;
END;
/
CREATE PROCEDURE v1
(
VehicleGroupID_Array IN tools.IntMap
)
IS
p_recordset SYS_REFCURSOR;
p_array IntList := tools.IntMapToList( VehicleGroupID_Array );
i BINARY_INTEGER;
BEGIN
-- Rest of your procedure using p_array instead of the associative array.
NULL;
END;
/
An Associative Array is defined by create or replace TYPE INNUMARRAY AS TABLE OF INTEGER INDEX BY PLS_INTEGER;
However, you cannot use Associative Arrays in TABLE(...)
expression. For this you must convert the Associative Array into a Nested Table (without INDEX BY PLS_INTEGER
), for example like this:
create or replace TYPE VehicleGroupID_TableType AS TABLE OF INTEGER;
...
VehicleGroupID_Table VehicleGroupID_TableType := VehicleGroupID_TableType();
BEGIN
FOR i IN VehicleGroupID_Array.FIRST..VehicleGroupID_Array.LAST LOOP
VehicleGroupID_Table.EXTEND;
VehicleGroupID_Table(VehicleGroupID_Table.LAST) := VehicleGroupID_Array(i);
END LOOP;
...
WHERE "VehicleGroupDetail"."VehicleGroupID" IN (
select column_value from table(VehicleGroupID_Table))
)
or shorter version:
WHERE "VehicleGroupDetail"."VehicleGroupID" MEMBER OF VehicleGroupID_Table