Re: Passing multi values into an in clause via a parameter in a store procedure

From: Mark C. Stock <mcstockX_at_Xenquery>
Date: Tue, 27 Jan 2004 19:11:41 -0500
Message-ID: <CP6dnc16fanGY4vdRVn-tw_at_comcast.com>


"Mark C. Stock" <mcstockX_at_Xenquery .com> wrote in message news:...
|
| "Mark C. Stock" <mcstockX_at_Xenquery .com> wrote in message news:...
| |
| | "Berend" <Berend.Brinkhuis_at_evatone.com> wrote in message
| | news:bdd9ac20.0401271301.22cdb65e_at_posting.google.com...
| | | I am trying to pass multi values into a where clause with an in clause
| | | in a store procedure to use in a Crystal report. This can change
| | | depending on the user. Maybe there is another way to pass multi
| | | values.
| | |
| | |
| | | CREATE OR REPLACE PROCEDURE eva_sp_wrk014_spec_test (
| | | p_eva_product_header_ids IN VARCHAR2,
| | | cur_spec_cd IN OUT
| | | sysadm.eva_pkg_wrk014_spec_test.ref_spec_spec_cd
| | | )
| | | AS
| | | BEGIN
| | | OPEN cur_spec_cd
| | | FOR
| | | SELECT *
| | | FROM sysadm.eva_product_header eph
| | | WHERE eph.eva_product_header_id in (p_eva_product_header_ids);
| | | END eva_sp_wrk014_spec_test;
| |
| | the IN clause requires separate values (i.e. a separate bind variable
 for
| | each value), and you've got all your values stuffed into one variable,
 the
| | equivalent of
| |
| | WHERE eph.eva_product_header_id in ( '00,01,23,43,09,33' )
| |
| | which attempts to find the value '00,01,23,43,09,33' not the one of the
| | individual values
| |
| | you'll need to rewrite your proc to use dynamic sql, or pull a trick
 like
| |
| | WHERE instr( p_eva_product_header_ids, cDelimiter ||
| | eph.eva_product_header_id || cDelimiter) > 0
| |
| | (the p_eva_product_header_ids parameter would need to have delimiters
| | between each value, and at the first and last position) -- not great for
| | performance if it's the only criteria
| |
| | other options: write the list of IDs to a temp table (perhaps within the
| | proc itself) and use a subquery or join to the temp table
| |
| | i think there's also a way these days to write a proc that returns a
 rowset
| | that can be used as a SQL table -- that might be another way to
 transform
| | the common separated list of ids into something useful in a non-dynamic
 SQL
| | statement
| |
| | or -- write a bunch of explicit ORs that can handle up to the max number
 or
| | IDs you think you'd be searching for, then parse out the IDs into local
| | variables
| |
| | -- mcs
| |
| |
|
| here's a reference to the using the TABLE and CAST operators/keywords to
| feed a the contents of a multi-valued variable to a SQL statement (thanks
 to
| another post by dan morgan) http://www.psoug.org/reference/conditions.html
|
| (forget about the temp table and explicit ORs suggestions)
|
| -- mcs
|
|

and here's an example that includes parsing the comma-separated input parameter into the PL/SQL table:

create or replace type vc4000tbl is table of varchar2(4000); /

create or replace procedure list_emps ( ip_depts in varchar2 ) is

  • declare and initialize PL/SQL table based on pre-created type

  tbl_deptno vc4000tbl := vc4000tbl();

  • variables needed for parsing offset number default 1; dlen number default length(ip_depts); slen number; c_sep constant varchar2(1) := ',';

begin

  • load deptno table from comma separated list
  • this could be wrapped in a procedure for generalization and reuse

  while offset < dlen
  loop

     slen := instr(ip_depts,c_sep,offset);
     if slen = 0
     then
        slen := dlen+1;
     end if;

  tbl_deptno.extend;
  tbl_deptno(tbl_deptno.count) := substr(ip_depts,offset,slen-offset);

     offset := slen+1;
  end loop;

  • use the deptno table in subquery with TABLE and CAST syntax
  • (for illustration -- this would likely be used with a ref cursor)

  for r1 in (

     select empno, ename, deptno
   from emp
   where deptno in (

      select column_value
    from table(cast(tbl_deptno as vc4000tbl))     )
   order by deptno, empno
   )
  loop

     dbms_output.put_line(
     r1.deptno
   || ': '
   || r1.empno

   || ' -- '
   || r1.ename);
  end loop;
end list_emps;
  • mcs
Received on Wed Jan 28 2004 - 01:11:41 CET

Original text of this message