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

Comment puis-je créer une clause WHERE dynamique ?

L'objet est d'assembler dynamiquement une instruction à partir d'un nombre variable de filtres dans la clause WHERE. Je ne sais pas où se situe la récursivité dans tout cela, je vais donc simplement utiliser un tableau pour gérer les paramètres :

SQL> create type qry_param as object
  2      (col_name varchar2(30)
  3      , col_value varchar(20))
  4  /

Type created.

SQL> create type qry_params as table of qry_param
  2  /

Type created.

SQL> 

Cette table est transmise à une fonction, qui boucle autour du tableau. Pour chaque entrée du tableau, il ajoute une ligne à la clause WHERE au format =''. Vous aurez probablement besoin d'un filtrage plus sophistiqué - différents opérateurs, conversion explicite du type de données, variables liées - mais c'est l'idée générale.

SQL> create or replace function get_emps
  2      (p_args in qry_params )
  3      return sys_refcursor
  4  as
  5      stmt varchar2(32767);
  6      rc sys_refcursor;
  7  begin
  8      stmt := ' select * from emp';
  9      for i in p_args.first()..p_args.last()
 10      loop
 11          if i = 1 then
 12              stmt := stmt || ' where ';
 13          else
 14              stmt := stmt || ' and ';
 15          end if;
 16          stmt := stmt || p_args(i).col_name
 17                       ||' = '''||p_args(i).col_value||'''';
 18      end loop;
 19      open rc for stmt;
 20      return rc;
 21  end get_emps;
 22  /

Function created.

SQL> 

Enfin, pour exécuter cette requête, nous devons remplir une variable locale de type tableau et renvoyer le résultat à un curseur de référence.

SQL> var l_rc refcursor
SQL> declare
  2      l_args qry_params := qry_params
  3                             (qry_param('DEPTNO', '50')
  4                                     , qry_param('HIREDATE', '23-MAR-2010'));
  5  begin
  6      :l_rc := get_emps(l_args);
  7  end;
  8  /

PL/SQL procedure successfully completed.


SQL> print l_rc

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      8041 FEUERSTEIN PLUMBER         7839 23-MAR-10       4250                    50
      8040 VERREYNNE  PLUMBER         7839 23-MAR-10       4500                    50

SQL>    

modifier

Dans le dernier paragraphe de leur question, l'OP dit qu'ils utilisent XML pour passer les critères. Cette exigence ne change pas radicalement la forme de mon implémentation d'origine. La boucle doit simplement lancer une requête XPath au lieu d'un tableau :

SQL> create or replace function get_emps
  2      (p_args in xmltype )
  3      return sys_refcursor
  4  as
  5      stmt varchar2(32767);
  6      rc sys_refcursor;
  7  begin
  8      stmt := ' select * from emp';
  9      for i in (select * from xmltable (
 10                       '/params/param'
 11                       passing p_args
 12                       columns
 13                           position for ordinality
 14                           , col_name varchar2(30) path '/param/col_name'
 15                           , col_value varchar2(30) path '/param/col_value'
 16                       )
 17               )
 18      loop
 19          if i.position = 1 then
 20            stmt := stmt || ' where ';
 21          else
 22            stmt := stmt || ' and ';
 23          end if;
 24          stmt := stmt || i.col_name
 25                     ||' = '''||i.col_value||'''';
 26      end loop;
 27      open rc for stmt;
 28      return rc;
 29  end get_emps;
 30  /

Function created.

SQL>

Comme on peut le voir, cette version renvoie les mêmes résultats qu'avant...

SQL> var l_rc refcursor
SQL> declare
  2      l_args xmltype := xmltype
  3                              ('<params>
  4                                  <param>
  5                                      <col_name>DEPTNO</col_name>
  6                                      <col_value>50</col_value>
  7                                  </param>
  8                                  <param>
  9                                      <col_name>HIREDATE</col_name>
 10                                      <col_value>23-MAR-2010</col_value>
 11                                  </param>
 12                              </params>');
 13  begin
 14    :l_rc := get_emps(l_args);
 15  end;
 16  /

PL/SQL procedure successfully completed.

SQL> print l_rc

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      8041 FEUERSTEIN PLUMBER         7839 23-MAR-10       4250                    50
      8040 VERREYNNE  PLUMBER         7839 23-MAR-10       4500                    50

SQL>