Merurz
Merurz

Reputation: 51

PLSQL - Use variable array on where clause IN

I am looking to use an array of values in the WHERE IN condition.

After research, I saw that I had to make a "CREATE TYPE", since a "TYPE" in local does not work. This solution does not suit me, I do not want to make a new TYPE in Oracle, since the database is used for an ERP/PGI I do not wish to pollute with my little need.

My request is the following:

DELETE vip_routage
 WHERE vip_tel_ext = w_array_tel(i)
   AND ((w_cp NOT IN ('14', '27', '50', '61', '76') 
   AND SUBSTR(VIP_CODE_POSTAL, 1, 2) IN ('14', '27', '50', '61', '76')) 
    OR (w_cp IN ('14', '27', '50', '61', '76') 
   AND SUBSTR(VIP_CODE_POSTAL, 1, 2) IN ('14', '27', '50', '61', '76') 
   AND TO_NUMBER(vip_dest1) < w_tri_ordre) 
    OR (w_cp NOT IN ('14', '27', '50', '61', '76') 
   AND SUBSTR(VIP_CODE_POSTAL, 1, 2) NOT IN ('14', '27', '50', '61', '76') 
   AND TO_NUMBER(vip_dest1) < w_tri_ordre));

It is the value "('14','27','50','61','76')" that I would like to set as a variable, but only in my program.

Do you have any ideas other than "CREATE TYPE"?

Upvotes: 0

Views: 1575

Answers (4)

Littlefoot
Littlefoot

Reputation: 142705

As you don't want to create your own type, use built-in one - sys.odcivarchar2list. For example, fetch employees who are either clerks or managers:

SQL> select deptno, empno, ename, job, sal
  2  from emp
  3  where job in (select *
  4                from table(sys.odcivarchar2list('CLERK', 'MANAGER'))
  5               );

    DEPTNO      EMPNO ENAME      JOB              SAL
---------- ---------- ---------- --------- ----------
        10       7934 MILLER     CLERK           1300
        30       7900 JAMES      CLERK            950
        20       7876 ADAMS      CLERK           1100
        20       7369 SMITH      CLERK            800
        10       7782 CLARK      MANAGER         2450
        30       7698 BLAKE      MANAGER         2850
        20       7566 JONES      MANAGER         2975

7 rows selected.

SQL>

If you want to declare a variable whose datatype is sys.odcivarchar2list (so, you're in a PL/SQL procedure), then

SQL> declare
  2    l_job sys.odcivarchar2list := sys.odcivarchar2list('CLERK', 'MANAGER');
  3    l_cnt number;
  4  begin
  5    select count(*)
  6      into l_cnt
  7      from emp
  8      where job in (select * from table(l_job));
  9
 10    dbms_output.put_line('Found ' || l_cnt || ' employees');
 11  end;
 12  /
Found 7 employees

PL/SQL procedure successfully completed.

SQL>

Upvotes: 4

astentx
astentx

Reputation: 6751

If you wish to pass this list of codes as a plain text (not as a bind variable of type collection), then you may use json_table function to expand the list into a table and use it as a general table with a subquery inside in predicate:

with function f
/*Just to emulate bind variable*/
return varchar2
as begin
  return q'('X','Y','Z')';
end;

lkp as (
  select *
  from json_table(
    '[' ||
    /*
      Your string goes here
      instead of invocation f()
    */
    f()
    || ']',
    '$[*]'
    columns (
      col varchar2(100) path '$'
    )
  )
)
select *
from dual
where dummy in (
  /*Filter by list*/
  select * from lkp
)
| DUMMY |
| :---- |
| X     |

db<>fiddle here

If you want to pass this codes as an array (collection in Oracle), then use built-in collection type sys.odcivarchar2list, but you'll need to prepare a bind variable of this type at the application side depending on the programming language (for example, here's an explanation with examples from the official docs for Python).

Upvotes: 0

MT0
MT0

Reputation: 167962

You can pass in a string (such as '14,27,50,61,76') as a bind variable and use LIKE to compare the delimited string:

DELETE FROM VIP_ROUTAGE
WHERE vip_TEL_EXT = w_array_tel(i)
AND (    ',' || :your_list || ',' NOT LIKE '%,' || w_cp || ',%'
    AND (  ',' || :your_list || ',' LIKE '%,' || SUBSTR(VIP_CODE_POSTAL,1,2) || '%,'
        OR to_number(vip_dest1) < w_tri_ordre))
OR  (    ',' || :your_list || ',' LIKE '%,' || w_cp || ',%'
    AND  ',' || :your_list || ',' LIKE '%,' || SUBSTR(VIP_CODE_POSTAL,1,2) || ',%'
    AND  to_number(vip_dest1) < w_tri_ordre)

db<>fiddle here

Upvotes: 0

OldProgrammer
OldProgrammer

Reputation: 12169

replace the first with clause and str with your string variable, you can do something like this:

with rws as (
  select '''14'',''27'',''50'',''61'',''76''' str from dual
),
item_list as (
  select regexp_substr (
           str,
           '[^,]+',
           1,
           level
         ) value
  from   rws
  connect by level <= 
    length ( str ) - length ( replace ( str, ',' ) ) + 1
)
delete from VIP_ROUTAGE
where vip_TEL_EXT = w_array_tel(i)
AND (
 (w_cp NOT IN  (select value from item_list)) ...

Upvotes: 1

Related Questions