簡體   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