'How to pass multiple values into one parameter in stored procedure (Oracle)
I have a parameter created for a stored procedure looking to allow user to pass in multiple inputs.
create procedure sp1 (p1 in varchar2)
as
begin
 select proc_id from proc_tbl where proc_id in (p1);
end;
The user expects to input multiple values separate by comma or space such as a1, b2, c3 in p1. All the PROC_ID stored in proc_tbl are in upper case.
The sp didn't run successfully and take in the inputs as a whole string.
In normal sql in clause we can just type out like this
select proc_id from proc_tbl where proc_id in ('A1', 'B2', 'C3')
How can we apply the same logic in oracle sp without case sensitivity?
Solution 1:[1]
From the database perspective, the csv list that are giving as argument is just another string, not a list of values. So you can't use IN.
One simple approach uses a regex function:
select proc_id from proc_tbl where regexp_like(p1, '^|,' || proc_id || ',|$', 'i');
The regex means:
proc_idis at the beginning of the parameter string (^) or is preceded by a comma- AND: 
proc_idis at the end of parameter string ($) or is followed by a comma 
Solution 2:[2]
From a SQL injection standpoint, you probably want to take some type of collection as a parameter. Or at least scan the input for reserve words. But after that you could just use your string as part of dynamic SQL like this:
create procedure sp1 (p1 in varchar2)
as
  TYPE lt_ResultTable is TABLE OF proc_table.proc_id%TYPE;
  l_tResult lt_ResultTable;
  l_nResult proc_table.proc_id%type;
begin
 EXECUTE IMMEDIATE 'select proc_id from proc_tbl where proc_id in ('||p1||')'
  BULK COLLECT INTO l_tResult;
 /*If you are guaranteed only one row will return from your query, you don't need to use a 
  nested table 
 EXECUTE IMMEDIATE 'select proc_id from proc_tbl where proc_id in ('||p1||')' INTO l_nResult;
*/
end;
    					Solution 3:[3]
Simple select without INTO clause would not even compile. However, there is a way to safely pass several values in one argument:
create or replace procedure sp1(p1 in varchar2) is
begin
for r in (
    select xt.proc_id
    from proc_tbl pt, xmltable(p1 columns proc_id varchar2(100) path '.') xt
    where pt.proc_id = xt.proc_id
)
loop
    dbms_output.put_line(r.proc_id);
end loop;
end;
/
    					Solution 4:[4]
If you have control over the parameters, it would be more robust to use a collection instead of a comma-separated list in a string. You can create your own collection or use one of the pre-built collections.
Schema
--drop table proc_tbl;
create table proc_tbl(proc_id number);
insert into proc_tbl values(1);
insert into proc_tbl values(2);
insert into proc_tbl values(3);
Procedure
--SYS.ODCINUMBERLIST is defind as a VARRAY(32767) OF NUMBER.
--Or you could create your own type, like: create type number_tab as table of number;
create or replace procedure sp1 (p1 in sys.odcinumberlist) as
    v_count number;
begin
    select count(*)
    into v_count
    from proc_tbl
    where proc_id in (select column_value from table(p1));
    dbms_output.put_line('Count: '||v_count);
end;
/
Sample Call
begin
    sp1(sys.odcinumberlist(1,2));
end;
/
Result
------
Count: 2
    					Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source | 
|---|---|
| Solution 1 | GMB | 
| Solution 2 | Del | 
| Solution 3 | Leonid | 
| Solution 4 | Jon Heller | 
