Well, there's another solution but I don't think it's very elegant.
It is necessary to use temporary table but the list of parameters in USING clause can be fixed and you can build the WHERE clause of the query dynamically.
The technique is:
1. Instead of OPEN RefCurVariable FOR ... USING use EXECUTE IMMEDIATE for inserting rows into temporary table
2. OPEN RefCurVariable FOR temporary table
The trick is:
In EXECUTE IMMEDIATE we can use PL/SQL block. In the block we must declare a "dummy" variable for each parameter used in USING clause. This avoids 'not all variables bound' error. Then, in the WHERE clause, we can use any bind variables even in any order.
A. user has defined conditions for ename and sal:Code:--the price for this solution: GLOBAL TEMPORARY TABLE drop table t_emp / create global temporary table t_emp on commit delete rows as select * from emp where 1=0 / -- create or replace package dyn_test as type t_ref_cursor is ref cursor; procedure dyn_sql(cur in out t_ref_cursor, sqltext varchar2, p_name char, p_sal number); end dyn_test; / -- create or replace package body dyn_test as procedure dyn_sql(cur in out t_ref_cursor, sqltext varchar2, p_name char, p_sal number) is block varchar2(200); begin --create PL/SQL block block := 'declare '|| 'dummy_name varchar2(10) := :NAME ; '|| 'dummy_sal number := :SALARY ; '|| 'begin '|| 'insert into t_emp ' || sqltext || ';' || 'end;'; execute immediate block using p_name, p_sal; open cur for select * from t_emp; end; end dyn_test; /B. The same, reverse order of predicatesCode:scott@oracle> var c refcursor scott@oracle> begin 2 dyn_test.dyn_sql( 3 cur => :c, 4 sqltext => 'select * from emp where ename like :NAME and sal>:SALARY', 5 p_name => 'S%', 6 p_sal => 1000); 7 end; 8 / PL/SQL procedure successfully completed. scott@oracle> print c EMPNO ENAME JOB MGR HIREDATE SAL ---------- ---------- --------- ---------- ------------------- ---------- 7788 SCOTT ANALYST 7566 09.12.1982 00:00:00 3000 scott@oracle> commit; -- TO DELETE ROWS FROM t_emp Commit complete.C. User has defined a condition for ename only:Code:scott@oracle> begin 2 dyn_test.dyn_sql( 3 cur => :c, 4 sqltext => 'select * from emp where sal>:SALARY and ename like :NAME', 5 p_name => 'S%', 6 p_sal => 1000); 7 end; 8 / PL/SQL procedure successfully completed. scott@oracle> print c EMPNO ENAME JOB MGR HIREDATE SAL ---------- ---------- --------- ---------- ------------------- ---------- 7788 SCOTT ANALYST 7566 09.12.1982 00:00:00 3000 scott@oracle> commit; Commit complete.D. User has defined a condition for sal only:Code:scott@oracle> begin 2 dyn_test.dyn_sql( 3 cur => :c, 4 sqltext => 'select * from emp where ename like :NAME', 5 p_name => 'S%', 6 p_sal => null); 7 end; 8 / PL/SQL procedure successfully completed. scott@oracle> print c EMPNO ENAME JOB MGR HIREDATE SAL ---------- ---------- --------- ---------- ------------------- ---------- 7369 SMITH CLERK 7902 17.12.1980 00:00:00 800 7788 SCOTT ANALYST 7566 09.12.1982 00:00:00 3000 scott@oracle> commit; Commit complete.Just a note to dynamic building of queries:Code:scott@oracle> begin 2 dyn_test.dyn_sql( 3 cur => :c, 4 sqltext => 'select * from emp where sal>:SALARY', 5 p_name => null, 6 p_sal => 1000); 7 end; 8 / PL/SQL procedure successfully completed. scott@oracle> print c EMPNO ENAME JOB MGR HIREDATE SAL ---------- ---------- --------- ---------- ------------------- ---------- 7499 ALLEN SALESMAN 7698 20.02.1981 00:00:00 1600 7521 WARD SALESMAN 7698 22.02.1981 00:00:00 1250 7566 JONES MANAGER 7839 02.04.1981 00:00:00 2975 7654 MARTIN SALESMAN 7698 28.09.1981 00:00:00 1250 7698 BLAKE MANAGER 7839 01.05.1981 00:00:00 2850 7782 CLARK MANAGER 7839 09.06.1981 00:00:00 2450 7788 SCOTT ANALYST 7566 09.12.1982 00:00:00 3000 7839 KING PRESIDENT 17.11.1981 00:00:00 5000 7844 TURNER SALESMAN 7698 08.09.1981 00:00:00 1500 7876 ADAMS CLERK 7788 12.01.1983 00:00:00 1100 7902 FORD ANALYST 7566 03.12.1981 00:00:00 3000 7934 MILLER CLERK 7782 23.01.1982 00:00:00 1300 12 rows selected.
My approved method is writing queries likeIf a parameter is undefined I delete the predicate for it and as a last step I replace all [] with a space.Code:select * from emp where 1=1 [ and ename like :ENAME ] [ and sal > :SALARY ]
The query is better maintainable than in case of dynamic building from strings;
I hope that's not too confusing, I really tried ...
Ales




Reply With Quote