Oracle
 sql >> Baza danych >  >> RDS >> Oracle

PL/SQL — Warunki opcjonalne w klauzuli where — bez dynamicznego sql?

Chociaż możesz to zrobić...

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

... wydajność przy użyciu dynamicznego SQL będzie zwykle lepsza , ponieważ wygeneruje bardziej ukierunkowany plan zapytań. W powyższym zapytaniu Oracle nie może powiedzieć, czy użyć indeksu w kodzie bcode lub lb, czy też wpisać lub edate i prawdopodobnie za każdym razem wykona pełne skanowanie tabeli.

Oczywiście musisz używaj zmiennych wiązania w zapytaniu dynamicznym, nie łącz wartości literałów w ciągu, w przeciwnym razie wydajność (oraz skalowalność i bezpieczeństwo) będą bardzo złe .

Żeby było jasne, dynamiczna wersja, którą mam na myśli, działałaby tak:

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;

Oznacza to, że zapytanie wynikowe będzie być "sargable" (dla mnie nowe słowo, muszę przyznać!), ponieważ wynikowe zapytanie będzie (na przykład):

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

Zgadzam się jednak, że w tym przykładzie może to wymagać do 16 twardych analiz. Klauzule "and :bv is null" są wymagane podczas używania natywnego dynamicznego SQL, ale można ich uniknąć używając DBMS_SQL.

Uwaga:użycie (1=1 or :bindvar is null) gdy zmienna bind ma wartość null, została zasugerowana w komentarzu przez Michala Pravdę, ponieważ pozwala to optymalizatorowi wyeliminować klauzulę.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Funkcja potokowa wywołująca inną funkcję potokową

  2. Wartość CLOB w out/return z plsql (określono nieprawidłowy lokalizator LOB:ORA-22275)

  3. pierwszy wiersz VS Następny wiersz VS numer wiersza

  4. Zapytanie w PHP Oracle zapytanie select wewnątrz pętli powolne

  5. Połącz oracle z pdo, z SID i INSTANCE_NAME