sql >> Databasteknik >  >> RDS >> Oracle

Är en CASE-sats och en DECODE ekvivalenta?

Kort svar, nej.

Det lite längre svaret är nästan.

Det visas bara att resultatet från varje påstående är identiskt. Om vi ​​använder DUMP-funktionen för att utvärdera de returnerade datatyperna ser du vad jag menar:

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 att datatypen för DECODE är 1, medan de två CASE-satserna "returnerar" en datatyp av 2. Med hjälp av Oracles Data Type Summary returnerar DECODE en VARCHAR2 (datatyp 1) medan CASE-satserna "returerar" " nummer (datatyp 2).

Jag antar att detta inträffar eftersom, som namnen antyder, DECODE är en funktion och CASE är det inte, vilket innebär att de har implementerats annorlunda internt. Det finns inget riktigt sätt att bevisa detta.

Du kanske tror att det här egentligen inte påverkar någonting. Om du behöver att det ska vara ett nummer kommer Oracle implicit att konvertera tecknet till ett tal enligt de implicita konverteringsreglerna, eller hur? Detta är inte heller sant, det fungerar inte i en UNION som datatyperna har att vara identisk; Oracle kommer inte att göra någon implicit konvertering för att göra det enkelt för dig. För det andra, här är vad Oracle säger om implicit konvertering:

Oracle rekommenderar att du anger explicita omvandlingar i stället för att förlita dig på implicita eller automatiska omvandlingar, av dessa skäl:

  • SQL-satser är lättare att förstå när du använder explicita datatypkonverteringsfunktioner.

  • Implicit datatypkonvertering kan ha en negativ inverkan på prestandan, särskilt om datatypen för ett kolumnvärde konverteras till en konstant snarare än tvärtom.

  • Implicit omvandling beror på det sammanhang i vilket den sker och kanske inte fungerar på samma sätt i alla fall. Till exempel kan implicit konvertering från ett datetime-värde till ett VARCHAR2-värde returnera ett oväntat år beroende på värdet på parametern NLS_DATE_FORMAT.

  • Algoritmer för implicit konvertering kan ändras mellan programvaruversioner och bland Oracle-produkter. Beteendet för explicita omvandlingar är mer förutsägbart.

Det är inte en vacker lista; men den näst sista poängen för mig fint in på dejter. Om vi ​​tar den föregående frågan och konverterar den till en som använder ett datum istället:

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;

Återigen, genom att använda DUMP på denna fråga returnerar CASE-satserna datatyp 12, ett DATUM. DECODE har konverterat sysdate till 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

Notera (i SQL Fiddle) att DATUM har konverterats till ett tecken med sessionerna NLS_DATE_FORMAT.

Att ha ett datum som implicit har omvandlats till en VARCHAR2 kan orsaka problem. Om du tänker använda TO_CHAR för att konvertera ditt datum till ett tecken, kommer din fråga att bryta där du inte förväntar dig 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

Likaså fungerar inte datumaritmetiken längre:

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

Intressant nog konverterar DECODE endast uttrycket till en VARCHAR2 om ett av de möjliga resultaten är NULL. Om standardvärdet är NULL händer inte detta. Till exempel:

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

Observera att DECODE har returnerat en datatyp på 13. Detta är inte dokumenterat men är, antar jag, en typ av datum eftersom datumaritmetik etc. fungerar.

Kort sagt, undvik DECODE om du möjligen kan; du kanske inte nödvändigtvis får de datatyper du förväntar dig. För att citera Tom Kyte:

Avkodning är något obskyrt -- CASE är väldigt tydligt. Saker som är lätta att göra i avkodning är lätta att göra i CASE, saker som är svåra eller nästan omöjliga att göra med avkodning är lätta att göra i CASE. CASE vinner logiskt sett.

Bara för att vara komplett finns det två funktionella skillnader mellan DECODE och CASE.

  1. DECODE kan inte användas inom PL/SQL.
  2. CASE kan inte användas för att jämföra nollvärden direkt

    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. Android-rumsdatabasen exporterar inte all data

  2. Sammanfoga/sammanfoga matrisvärden under gruppering/aggregering

  3. Beräkna en löpande summa i MySQL

  4. INITCAP() – Konvertera till initiala Caps i PostgreSQL