sql >> Databasteknik >  >> RDS >> Oracle

PL/SQL - Valfria villkor i where-klausul - utan dynamisk sql?

Även om du kunde göra det här...

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

... prestanda med dynamisk SQL kommer vanligtvis att vara bättre , eftersom det kommer att generera en mer riktad frågeplan. I ovanstående fråga kan Oracle inte säga om man ska använda ett index på bcode eller lb eller typ eller edate, och kommer förmodligen att utföra en fullständig tabellsökning varje gång.

Självklart måste du använd bindningsvariabler i din dynamiska fråga, inte sammanfoga de bokstavliga värdena i strängen, annars blir prestanda (och skalbarhet och säkerhet) mycket dålig .

För att vara tydlig skulle den dynamiska versionen jag har i åtanke fungera så här:

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 att resultatfrågan kommer vara "sargable" (ett nytt ord för mig måste jag erkänna!) eftersom den resulterande frågekörningen blir (till exempel):

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

Jag accepterar dock att detta kan kräva upp till 16 hårda analyser i detta exempel. "och :bv är null"-satser krävs när du använder inbyggd dynamisk SQL, men kan undvikas genom att använda DBMS_SQL.

Obs:användningen av (1=1 or :bindvar is null) när bindningsvariabeln är null föreslogs i en kommentar av Michal Pravda, eftersom den tillåter optimeraren att eliminera klausulen.



  1. hur man skapar 3 beroende dropdown-lista med PHP ajax JQUERY?

  2. få följare på twitter som att använda MySQL

  3. VISA TABELLER i MariaDB

  4. Ange värde =värde +1 i bookshelf.js