How can I create a “dynamic” WHERE clause?

前端 未结 5 1178
有刺的猬
有刺的猬 2020-12-29 17:44

First: Thanks!

I finished my other project and the big surprise: now everything works as it should :-) Thanks to some helpful thinkers of SO!

5条回答
  •  一生所求
    2020-12-29 18:20

    The object is to dynamically assemble a statement from a variable number of filters in the WHERE clause. I'm not sure where recursion fits into all this, so I will just use an array to handle the parameters:

    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> 
    

    This table is passed to a function, which loops around the array. For each entry in the array it appends a line to the WHERE clause in the format = ''. Probably you will require more sophisticated filtering - different operators, explicit data type conversion, bind variables - but this is the general idea.

    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> 
    

    Finally to execute this query we need to populate a local variable of the array type and return the result to a ref cursor.

    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>    
    

    edit

    In the last paragraph of their question the OP says they are using XML to pass the criteria. This requirement doesn't dramatically change the shape of my original implementation. The loop simply needs to drive off an XPath query instead of an array:

    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>
    

    As can be seen, this version returns the same results as before...

    SQL> var l_rc refcursor
    SQL> declare
      2      l_args xmltype := xmltype
      3                              ('
      4                                  
      5                                      DEPTNO
      6                                      50
      7                                  
      8                                  
      9                                      HIREDATE
     10                                      23-MAR-2010
     11                                  
     12                              ');
     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>
    

提交回复
热议问题