Trong khi bạn có thể làm điều này ...
select num
from (select distinct q.num
from cqqv q
where 1=1
and (:bcode is null or q.bcode = :bcode)
and (:lb is null or q.lb = :lb)
and (:type is null or q.type = :type)
and (:edate is null or q.edate > :edate - 30)
order by dbms_random.value()) subq
where rownum <= :numrows
... hiệu suất sử dụng SQL động thường sẽ tốt hơn , vì nó sẽ tạo ra một kế hoạch truy vấn được nhắm mục tiêu hơn. Trong truy vấn trên, Oracle không thể cho biết nên sử dụng chỉ mục trên bcode hay lb hay type hoặc edate, và có thể sẽ thực hiện quét toàn bộ bảng mỗi lần.
Tất nhiên, bạn phải sử dụng các biến liên kết trong truy vấn động của bạn, không nối các giá trị chữ vào chuỗi, nếu không hiệu suất (và khả năng mở rộng và bảo mật) sẽ rất kém .
Nói rõ hơn, phiên bản động mà tôi nghĩ đến sẽ hoạt động như sau:
declare
rc sys_refcursor;
q long;
begin
q := 'select num
from (select distinct q.num
from cqqv q
where 1=1';
if p_bcode is not null then
q := q || 'and q.bcode = :bcode';
else
q := q || 'and (1=1 or :bcode is null)';
end if;
if p_lb is not null then
q := q || 'and q.lb = :lb';
else
q := q || 'and (1=1 or :lb is null)';
end if;
if p_type is not null then
q := q || 'and q.type = :type';
else
q := q || 'and (1=1 or :type is null)';
end if;
if p_edate is not null then
q := q || 'and q.edate = :edate';
else
q := q || 'and (1=1 or :edate is null)';
end if;
q := q || ' order by dbms_random.value()) subq
where rownum <= :numrows';
open rc for q using p_bcode, p_lb, p_type, p_edate, p_numrows;
return rc;
end;
Điều này có nghĩa là truy vấn kết quả sẽ là "sargable" (một từ mới đối với tôi, tôi phải thừa nhận!) vì kết quả chạy truy vấn sẽ là (ví dụ):
select num
from (select distinct q.num
from cqqv q
where 1=1
and q.bcode = :bcode
and q.lb = :lb
and (1=1 or :type is null)
and (1=1 or :edate is null)
order by dbms_random.value()) subq
where rownum <= :numrows
Tuy nhiên, tôi chấp nhận rằng điều này có thể yêu cầu tối đa 16 phân đoạn cứng trong ví dụ này. Các mệnh đề "và:bv là null" được yêu cầu khi sử dụng SQL động gốc, nhưng có thể tránh được bằng cách sử dụng DBMS_SQL.
Lưu ý:việc sử dụng (1=1 or :bindvar is null)
khi biến liên kết là null được đề xuất trong một nhận xét của Michal Pravda, vì nó cho phép trình tối ưu hóa loại bỏ mệnh đề.