Това наистина е по-голяма тема, но това е подходът, който според мен е най-лесният за прилагане и работи добре. Номерът е да използвате динамичен SQL, но го прилагайте така, че винаги да предавате един и същ брой параметри (необходими) И вие позволявате на Oracle да късо съединение, когато нямате стойност за параметър (това, което ви липсва настоящият ви подход). Например:
set serveroutput on
create or replace procedure test_param(p1 in number default null, p2 in varchar2 default null) as
l_sql varchar2(4000);
l_cur sys_refcursor;
l_rec my_table%rowtype;
l_ctr number := 0;
begin
l_sql := 'select * from my_table where 1=1';
if (p1 is not null) then
l_sql := l_sql || ' and my_num_col = :p1';
else
-- short circuit for optimizer (1=1)
l_sql := l_sql || ' and (1=1 or :p1 is null)';
end if;
if (p2 is not null) then
l_sql := l_sql || ' and name like :p2';
else
-- short circuit for optimizer (1=1)
l_sql := l_sql || ' and (1=1 or :p2 is null)';
end if;
-- show what the SQL query will be
dbms_output.put_line(l_sql);
-- note always have same param list (using)
open l_cur for l_sql using p1,p2;
-- could return this cursor (function), or simply print out first 10 rows here for testing
loop
l_ctr := l_ctr + 1;
fetch l_cur
into l_rec;
exit when l_cur%notfound OR l_ctr > 10;
dbms_output.put_line('Name is: ' || l_rec.name || ', Address is: ' || l_rec.address1);
end loop;
close l_cur;
end;
За да тествате, просто го стартирайте. Например:
set serveroutput on
-- using 0 param
exec test_param();
-- using 1 param
exec test_param(123456789);
-- using 2 params
exec test_param(123456789, 'ABC%');
В моята система използваната таблица е над 100 мм редове с индекс в полето за число и поле за име. Връща се почти мигновено. Също така имайте предвид, че може да не искате да правите избор *, ако не се нуждаете от всички колони, но аз съм малко мързелив и използвам %rowtype за този пример.
Надявам се това да помогне