You Asked
Hi Tom,I have a web application connecting to a Oracle DB.
I have a search screen where user can enter any search criterion and submit the information.
The information is collected and passed to an Oracle Stored Proc. where a dynamic query is formed based on the search citerion passed.
Ex
if user entered emp no then
the dynamic query formed would be
select * from emp where empNo = p_empno;
If the user entered emp no and salary then
the dynamic query formed would be
select * from emp where empNo = p_empno and sal = p_salary;
What we are doing is forming the where predicate string dynamically based on user input and using execute immediate to execute above dynamically formed query.
I know this dynamic query would be inefficient as each query would be unique which means hard parsed which means low efficiency.
Actually my search screen has a lot of fields about 50 different fields.
(1)Since p_empno etc are parameters to stored proc are these turned into bind varaibles even though I am using execute immediate ?
(2)
I did search on the net for any help .
One article said a generic search could be formed like this
select * from emp where ename = NVL(:n,ename) and deptno = NVL(:d,deptno) and empno = NVL(:e,empno);
but would be inefficient as it would always lead to full table scans.
Is this true?
(2) I think using this would be better than above since it uses bind variables.
Form the query string like this
select * from emp where ename = :n and deptno = :d and empno = :e using p_ename,p_deptno, p_empno
and then execute above formed dynamic string using execute immediate.
(3) Would you suggest any better way of doing this generic search.
As always thank you for your valuable time in helping out the newbies.
Thank you a million times.
Regards
and we said...
Basically, you will use a ref cursor, and you will build the query dynamically, the query will resemble:where (1=1 or :COLUMN_NAME1 is null) and ( column_name2 = :COLUMN_NAME2 )
you would use the first form:
(1=1 or :column_name1 is null)
when the user did not supply the input to constrain against column_name1 and the second form:
( column_name2 = :COLUMN_NAME2 )
when then do. The optimizer will see (1=1 or ...) and optimize that away, it will be as it is was never there. But, it will give you a bind place holder.
So, if you had three inputs (c1, c2, c3) you would build a query like:
select ... from ... where (1=1 or :c1 is null) and (c2 = :c2) and (c3 = :c3)
and then:
open C for that_string using p_c1, p_c2, p_c3;
and that would process a query whereby the end user supplied c2 and c3 - but not c1. And it would do it as efficiently as possible - using an index on c2 or c3 or c2+c3 if appropriate (you get the best plan based on the inputs that are provided)
by the way - BOTH of your examples used bind variables. But they are not equivalent (the second one would not return the right answer, and the first one would be slow - a full scan every time).