To pass a list/array of ids from C# into Oracle PL/SQL procedure, you have to define an associative array type e.g. a table with integer indexing:
TYPE Ids_t_a is table of Number index by binary_integer;
I want to write a stored proc which wraps a query like the following:
SELECT Id, Name from Person where Id in Ids;
I know basic SQL but am not a PL/SQL expert at all and table-valued types are beyond me. I tried:
PROCEDURE GetData(Ids in Ids_t_a, results out sys_refcursor) IS
BEGIN
Open Results for
SELECT Id, Name from Person p where p.Id in Ids;
END;
But this gives an error "expression is of wrong type" and that seems to be because you cannot use an associative array this way.
What additional steps do I need to run my desired query against my input arguments?
In Oracle, there are two scopes where statements can be evaluated:
An associative array is a PL/SQL data type and can only be used in the PL/SQL scope. It CANNOT be used in SQL statements so it is impossible to use an associative array directly as you are attempting (and, for some unknown reason, C# does not support passing non-associative arrays).
You need to convert the associative array collection type that you pass in from C# to a non-associative array collection type (either a nested-table collection type or a VARRAY collection type that you have defined in the SQL scope) in the PL/SQL scope and then use the non-associative array in the SQL scope.
You could use a built-in collection type like
SYS.ODCINUMBERTYPEor you can define your own collection in the SQL scope:Then you can create your package and procedure and a helper function to perform the conversion:
Then the package body:
Note: if you use a
VARRAYcollection data type, such as the built-inSYS.ODCINUMBERLISTtype, then you cannot use theMEMBER OFoperator as that only supports nested-table collection types. Instead you would have to use a sub-query (or a join) and a table collection expression. For example:Open Results for SELECT p.Id, p.Name FROM Person p INNER JOIN TABLE(map_ids(ids)) i ON p.id = i.COLUMN_VALUE;If you have the sample data:
Then you can call your procedure (either from C# or from a PL/SQL block) and pass an associative array and retrieve the cursor:
Which outputs:
fiddle