Oracle
 sql >> Base de données >  >> RDS >> Oracle

Comment utiliser des paramètres dans une clause 'where value in...'?

L'utilisation de SQL dynamique est l'approche la plus simple du point de vue du codage. Le problème avec SQL dynamique, cependant, est que vous devez analyser chaque version distincte de la requête, ce qui non seulement a le potentiel de taxer votre CPU, mais a le potentiel d'inonder votre pool partagé avec de nombreuses instructions SQL non partageables, poussant out que vous souhaitez mettre en cache, ce qui provoque davantage d'analyses difficiles et d'erreurs de fragmentation du pool partagé. Si vous l'exécutez une fois par jour, ce n'est probablement pas un problème majeur. Si des centaines de personnes l'exécutent des milliers de fois par jour, c'est probablement une préoccupation majeure.

Un exemple de l'approche SQL dynamique

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.

Vous pouvez également utiliser une collection. Cela a l'avantage de générer un seul curseur partageable, vous n'avez donc pas à vous soucier de l'analyse difficile ou de l'inondation du pool partagé. Mais cela nécessite probablement un peu plus de code. La façon la plus simple de gérer les collections

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.

Si, d'un autre côté, vous devez vraiment commencer avec une liste de valeurs séparées par des virgules, vous devrez alors analyser cette chaîne dans une collection avant de pouvoir l'utiliser. Il existe différentes façons d'analyser une chaîne délimitée - ma préférée est d'utiliser des expressions régulières dans une requête hiérarchique, mais vous pouvez certainement également écrire une approche procédurale

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.