繁体   English   中英

如何创建“动态”WHERE 子句?

[英]How can I create a “dynamic” WHERE clause?

第一:谢谢!

我完成了我的另一个项目和一个大惊喜:现在一切正常:-) 感谢 SO 的一些有用的思想家!

所以我开始下一个项目。

我想得到这样的东西:

SELECT * FROM tablename WHERE field1=content AND field2=content2 ...

正如您所注意到的,这可能是一个很长的 where 子句。 tablename 是一个静态属性,不会改变。 field1 , field2 , ... (!) 并且内容可以改变。

所以我需要一个选项来在递归函数内在 PL/SQL 中构建 SQL 语句。 我真的不知道要搜索什么,所以我在这里要求链接甚至一个词来搜索..

请不要开始争论递归函数是否真的需要或它的缺点是什么 - 这不是问题;-)

如果你能帮我创建一个类似 SQL-String 的东西,它以后将能够成功执行 SELECT,这将是非常好的!

我能够通过递归函数并每次生成更长的字符串,但我无法从中生成 SQL 语句。

哦,还有一件事:我通过 xmlType(xmldom.domdocument 等)获取字段和内容我可以从 xmltype 获取字段和内容,例如在 clob 中

目标是从 WHERE 子句中的可变数量的过滤器中动态地组装一条语句。 我不确定递归在哪里适合所有这些,所以我将只使用一个数组来处理参数:

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> 

该表被传递给一个函数,该函数在数组周围循环。 对于数组中的每个条目,它以 <name> = '<value>' 格式将一行附加到 WHERE 子句。 可能您需要更复杂的过滤——不同的运算符、显式数据类型转换、绑定变量——但这是总体思路。

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> 

最后,为了执行这个查询,我们需要填充一个数组类型的局部变量并将结果返回给一个引用游标。

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>    

编辑

在他们问题的最后一段中,OP 表示他们正在使用 XML 来通过标准。 这个要求不会显着改变我原始实现的形状。 循环只需要驱动一个 XPath 查询而不是一个数组:

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>

可以看出,这个版本返回的结果和以前一样......

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>

使用其他答案中显示的动态 SQL 并仍然使用绑定变量(这是一个很好的做法)的一种有用方法是使用 WITH 子句来绑定变量。 这有两个目的:首先,它让您每次都绑定所有变量,无论您是否使用它们; 其次,它允许您按名称引用您的绑定,因此如果您需要多次引用一个,您仍然只需绑定一次。

一个例子:

create or replace sample_function (
   v_field1 tablename.field1%type default 1,
   v_field2 tablename.field2%type default null,
   v_field3 tablename.field3%type default 'some value') is
   v_base_query varchar2(2000) := 
      'with binds as (
          select :bind1 as field1,
                 :bind2 as field2,
                 :bind3 as field3
            from dual)
       select t.field4, b.field3 from tablename t, binds b
       where 1=1 ';
   v_where varchar2(2000);
   cur_tablename sys_refcursor;
begin
   if v_field1 is not null then
      v_where := v_where || ' and t.field1 = b.field1';
   end if;
   if v_field2 is not null then
      v_where := v_where || ' and t.field2 = b.field2';
   end if;
   if v_field3 is not null then
      v_where := v_where || ' and t.field3 <= b.field3';
   end if;
   open cur_tablename for v_base_query || v_where
      using v_field1, v_field2, v_field3;
   return cur_tablename;
end sample_function;
SELECT * FROM emp
  
WHERE (1 = 1 OR job = 'SALESMAN')

AND (1 = 1 OR TO_CHAR(hiredate,'YYYYMMDD') = '19810220')
AND (1 = 0 OR TO_CHAR(hiredate,'YYYYMMDD') > '19820101')
AND (1 = 1 OR sal = 1600); 

http://www.akadia.com/services/dyn_modify_where_clause.html
看看这篇精彩的文章。

您可以创建一个游标,然后动态创建一个 sql 字符串,然后使用

mycur is ref cursor
open mycur for 'select ... from ... where '||dynamic_string
fetch mycur ...

或者

您可以使用

execute immediate 'select id from ... where '||dynamic_string bulk collect into mylist
where mytype is for example>
Type Mytype is table of number
mylist Mytype;

在 PLSQL 中,您可以执行以下操作:

declare
  l_statement varchar2(32767);
begin
  l_statement := 'SELECT * FROM tablename WHERE field1=:a AND field2=:b';

  -- you now have you query. Put in the values that you like.
  execute immediate l_statement
  using 'value1','value2';
end;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM