第一:谢谢!
我完成了我的另一个项目并且大惊喜:现在一切正常:-) 感谢一些有用的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
答案 0 :(得分:4)
该对象是从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>格式向WHERE子句附加一行。 ='< value>'。可能你需要更复杂的过滤 - 不同的运算符,显式数据类型转换,绑定变量 - 但这是一般的想法。
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>
答案 1 :(得分:3)
使用动态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;
答案 2 :(得分:2)
您可以创建游标,然后动态创建一个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;
答案 3 :(得分:2)
SELECT * FROM emp
WHERE(1 = 1 OR job =&#39; SALESMAN&#39;)
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
看看这篇精彩的文章。
答案 4 :(得分:0)
在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;