Oracle
 sql >> Database >  >> RDS >> Oracle

Come utilizzare i parametri in una clausola "where value in..."?

L'uso dell'SQL dinamico è l'approccio più semplice dal punto di vista della codifica. Il problema con l'SQL dinamico, tuttavia, è che devi analizzare a fondo ogni versione distinta della query che non solo ha il potenziale di tassare la tua CPU, ma ha il potenziale per inondare il tuo pool condiviso con molte istruzioni SQL non condivisibili, spingendo out istruzioni che desideri memorizzare nella cache, causando analisi più difficili ed errori di frammentazione del pool condiviso. Se lo esegui una volta al giorno, probabilmente non è un grosso problema. Se centinaia di persone lo eseguono migliaia di volte al giorno, è probabilmente una delle principali preoccupazioni.

Un esempio dell'approccio SQL dinamico

SQL> ed
Wrote file afiedt.buf

  1  declare
  2    l_deptnos  varchar2(100) := '10,20';
  3    l_rc       sys_refcursor;
  4    l_dept_rec dept%rowtype;
  5  begin
  6    open l_rc for 'select * from dept where deptno in (' || l_deptnos || ')';
  7    loop
  8      fetch l_rc into l_dept_rec;
  9      exit when l_rc%notfound;
 10      dbms_output.put_line( l_dept_rec.dname );
 11    end loop;
 12    close l_rc;
 13* end;
SQL> /
ACCOUNTING
RESEARCH

PL/SQL procedure successfully completed.

In alternativa, puoi utilizzare una raccolta. Questo ha il vantaggio di generare un singolo cursore condivisibile in modo da non doversi preoccupare di un'analisi difficile o di inondare il pool condiviso. Ma probabilmente richiede un po' più di codice. Il modo più semplice per gestire le collezioni

SQL> ed
Wrote file afiedt.buf

  1  declare
  2    l_deptnos  tbl_deptnos := tbl_deptnos(10,20);
  3  begin
  4    for i in (select *
  5                from dept
  6               where deptno in (select column_value
  7                                  from table(l_deptnos)))
  8    loop
  9      dbms_output.put_line( i.dname );
 10    end loop;
 11* end;
SQL> /
ACCOUNTING
RESEARCH

PL/SQL procedure successfully completed.

Se, d'altra parte, devi davvero iniziare con un elenco di valori separati da virgole, dovrai analizzare quella stringa in una raccolta prima di poterla utilizzare. Esistono vari modi per analizzare una stringa delimitata:il mio preferito è usare espressioni regolari in una query gerarchica, ma potresti anche scrivere un approccio procedurale

SQL> ed
Wrote file afiedt.buf

  1  declare
  2    l_deptnos     tbl_deptnos;
  3    l_deptno_str  varchar2(100) := '10,20';
  4  begin
  5    select regexp_substr(l_deptno_str, '[^,]+', 1, LEVEL)
  6      bulk collect into l_deptnos
  7      from dual
  8   connect by level <= length(replace (l_deptno_str, ',', NULL));
  9    for i in (select *
 10                from dept
 11               where deptno in (select column_value
 12                                  from table(l_deptnos)))
 13    loop
 14      dbms_output.put_line( i.dname );
 15    end loop;
 16* end;
 17  /
ACCOUNTING
RESEARCH

PL/SQL procedure successfully completed.