sql >> Database teknologi >  >> RDS >> Oracle

PL/SQL - Valgfri betingelser i where-klausul - uden dynamisk sql?

Mens du kunne gøre dette...

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

... ydeevnen ved brug af dynamisk SQL vil normalt være bedre , da det vil generere en mere målrettet forespørgselsplan. I ovenstående forespørgsel kan Oracle ikke fortælle, om der skal bruges et indeks på bcode eller lb eller type eller edate, og vil sandsynligvis udføre en fuld tabelscanning hver gang.

Selvfølgelig skal du brug bindevariabler i din dynamiske forespørgsel, ikke sammenkæde de bogstavelige værdier i strengen, ellers vil ydeevne (og skalerbarhed og sikkerhed) være meget dårlig .

For at være klar, ville den dynamiske version, jeg har i tankerne, fungere sådan her:

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;

Det betyder, at resultatforespørgslen vil være "sargable" (et nyt ord for mig må jeg indrømme!), da den resulterende forespørgsel vil være (for eksempel):

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

Jeg accepterer dog, at dette kan kræve op til 16 hårde parses i dette eksempel. "og :bv er null"-sætninger er påkrævet, når du bruger indbygget dynamisk SQL, men kan undgås ved at bruge DBMS_SQL.

Bemærk:brugen af ​​(1=1 or :bindvar is null) når bindevariablen er null, blev foreslået i en kommentar af Michal Pravda, da det tillader optimeringsværktøjet at fjerne klausulen.



  1. masseopdatering af en liste over værdier fra en liste over id'er

  2. Sådan genopbygger du en inkonsekvent PostgreSQL-slave

  3. ListArray Gemmer samme registreringer

  4. Sådan konverteres små bogstaver til store bogstaver i SQL Server - STORE ()