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

Er en CASE-sætning og en DECODE ækvivalente?

Kort svar, nej.

Det lidt længere svar er næsten.

Det vises kun at resultatet opnået fra hver udsagn er identisk. Hvis vi bruger DUMP-funktionen til at evaluere de returnerede datatyper, vil du se, hvad jeg mener:

SQL> select dump(case 1 when 2 then null else 0 end) as simple_case
  2       , dump(case when 1 = 2 then null else 0 end) as searched_case
  3       , dump(decode(1, 2, null, 0)) as decode
  4    from dual;

SIMPLE_CASE        SEARCHED_CASE      DECODE
------------------ ------------------ -----------------
Typ=2 Len=1: 128   Typ=2 Len=1: 128   Typ=1 Len=1: 48

SQL Fiddle

Du kan se, at datatypen for DECODE er 1, hvorimod de to CASE-sætninger "returnerer" en datatype på 2. Ved at bruge Oracles Data Type Summary returnerer DECODE en VARCHAR2 (datatype 1), mens CASE-sætningerne "returnerer" " numre (datatype 2).

Jeg antager, at dette sker, fordi, som navnene antyder, DECODE er en funktion og CASE er det ikke, hvilket betyder, at de er blevet implementeret anderledes internt. Der er ingen reel måde at bevise dette på.

Du tror måske, at dette ikke rigtig påvirker noget. Hvis du har brug for, at det er et tal, vil Oracle implicit konvertere tegnet til et tal under de implicitte konverteringsregler, ikke? Dette er heller ikke sandt, det vil ikke fungere i en UNION, som datatyperne har at være identisk; Oracle vil ikke foretage nogen implicit konvertering for at gøre tingene nemme for dig. For det andet, her er hvad Oracle siger om implicit konvertering:

Oracle anbefaler, at du angiver eksplicitte konverteringer i stedet for at stole på implicitte eller automatiske konverteringer af disse grunde:

  • SQL-sætninger er nemmere at forstå, når du bruger eksplicitte datatypekonverteringsfunktioner.

  • Implicit datatypekonvertering kan have en negativ indvirkning på ydeevnen, især hvis datatypen for en kolonneværdi konverteres til en konstant i stedet for omvendt.

  • Implicit konvertering afhænger af den kontekst, den finder sted i, og fungerer muligvis ikke på samme måde i alle tilfælde. For eksempel kan implicit konvertering fra en datetime-værdi til en VARCHAR2-værdi returnere et uventet år afhængigt af værdien af ​​NLS_DATE_FORMATparameteren.

  • Algoritmer til implicit konvertering kan ændres på tværs af softwareudgivelser og blandt Oracle-produkter. Eksplicitte konverteringers adfærd er mere forudsigelig.

Det er ikke en køn liste; men det næstsidste point bringer mig fint på dates. Hvis vi tager den forrige forespørgsel og konverterer den til en, der bruger en dato i stedet:

select case sysdate when trunc(sysdate) then null 
                    else sysdate 
       end as simple_case
     , case when sysdate = trunc(sysdate) then null 
            else sysdate 
       end as searched_case
     , decode(sysdate, trunc(sysdate), null, sysdate) as decode
  from dual;

Endnu en gang, ved at bruge DUMP på denne forespørgsel, returnerer CASE-sætningerne datatype 12, en DATE. DECODE har konverteret sysdate ind i en VARCHAR2.

SQL> select dump(case sysdate when trunc(sysdate) then null
  2                           else sysdate
  3              end) as simple_case
  4       , dump(case when sysdate = trunc(sysdate) then null
  5                   else sysdate
  6              end) as searched_case
  7       , dump(decode(sysdate, trunc(sysdate), null, sysdate)) as decode
  8    from dual;

SIMPLE_CASE          
---------------------------------- 
Typ=12 Len=7: 120,112,12,4,22,18,7 
SEARCHED_CASE
---------------------------------- 
Typ=12 Len=7: 120,112,12,4,22,18,7
DECODE
---------------------------------- 
Typ=1 Len=19: 50,48,49,50,45,49,50,45,48,52,32,50,49,58,49,55,58,48,54

SQL Fiddle

Bemærk (i SQL Fiddle), at DATE er blevet konverteret til et tegn ved hjælp af sessionerne NLS_DATE_FORMAT.

At have en dato, der implicit er blevet konverteret til en VARCHAR2, kan forårsage problemer. Hvis du har til hensigt at bruge TO_CHAR til at konvertere din dato til et tegn, vil din forespørgsel bryde, hvor du ikke forventer det.

SQL> select to_char( decode( sysdate
  2                         , trunc(sysdate), null
  3                         , sysdate )
  4                 , 'yyyy-mm-dd') as to_char
  5    from dual;
select to_char( decode( sysdate
                *
ERROR at line 1:
ORA-01722: invalid number

SQL Fiddle

Ligeledes virker dato-aritmetik ikke længere:

SQL>
SQL>
SQL> select decode(sysdate, trunc(sysdate), null, sysdate) + 1 as decode
  2    from dual;
select decode(sysdate, trunc(sysdate), null, sysdate) + 1 as decode
       *
ERROR at line 1:
ORA-01722: invalid number

SQL Fiddle

Interessant nok konverterer DECODE kun udtrykket til en VARCHAR2, hvis et af de mulige resultater er NULL. Hvis standardværdien er NULL, sker dette ikke. For eksempel:

SQL> select decode(sysdate, sysdate, sysdate, null) as decode
  2    from dual;

DECODE
-------------------
2012-12-04 21:18:32

SQL> select dump(decode(sysdate, sysdate, sysdate, null)) as decode
  2    from dual;

DECODE
------------------------------------------    
Typ=13 Len=8: 220,7,12,4,21,18,32,0

SQL Fiddle

Bemærk, at DECODE har returneret en datatype på 13. Dette er ikke dokumenteret, men jeg antager, at det er en type dato, da datoregning osv. virker.

Kort sagt, undgå DECODE, hvis du overhovedet kan; du får muligvis ikke nødvendigvis de datatyper, du forventer. For at citere Tom Kyte:

Afkodning er noget obskur -- CASE er meget meget tydeligt. Ting, der er lette at gøre i afkodning, er nemme at gøre i CASE, ting, der er svære eller næsten umulige at gøre med afkodning, er nemme at gøre i CASE. CASE, logisk set, vinder hænder ned.

Bare for at være komplet er der to funktionelle forskelle mellem DECODE og CASE.

  1. DECODE kan ikke bruges i PL/SQL.
  2. CASE kan ikke bruges til at sammenligne nuller direkte

    SQL> select case null when null then null else 1 end as case1
      2        , case when null is null then null else 1 end as case2
      3        , decode(null, null, null, 1) as decode
      4    from dual
      5         ;
    
         CASE1      CASE2 DECODE
    ---------- ---------- ------
             1
    

    SQL Fiddle



  1. TRUNC(tal) Funktion i Oracle

  2. DO'er og DONT'er for indekser

  3. Oprettelse af en trigger i Oracle Express

  4. Emuler MySQL LIMIT-klausul i Microsoft SQL Server 2000