sql >> Database >  >> RDS >> Oracle

Zijn een CASE-statement en een DECODE equivalent?

Kort antwoord, nee.

Het iets langere antwoord is bijna.

Het verschijnt alleen dat het resultaat van elke uitspraak identiek is. Als we de DUMP-functie gebruiken om de geretourneerde gegevenstypen te evalueren, ziet u wat ik bedoel:

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

U kunt zien dat het gegevenstype van DECODE 1 is, terwijl de twee CASE-statements een datatype van 2 "retourneren". Met behulp van Oracle's Data Type Summary, retourneert DECODE een VARCHAR2 (datatype 1) terwijl de CASE-statements "retourneren" " nummers (gegevenstype 2).

Ik neem aan dat dit gebeurt omdat, zoals de namen suggereren, DECODE een functie is en CASE niet, wat impliceert dat ze intern anders zijn geïmplementeerd. Er is geen echte manier om dit te bewijzen.

Je zou kunnen denken dat dit helemaal niets uitmaakt. Als het een getal moet zijn, zal Oracle het teken impliciet naar een getal converteren volgens de impliciete conversieregels, toch? Dit is ook niet waar, het zal niet werken in een UNION aangezien de datatypes hebben identiek zijn; Oracle zal geen impliciete conversie uitvoeren om het u gemakkelijk te maken. Ten tweede, dit is wat Oracle zegt over impliciete conversie:

Oracle raadt u om de volgende redenen aan om expliciete conversies op te geven in plaats van te vertrouwen op impliciete of automatische conversies:

  • SQL-instructies zijn gemakkelijker te begrijpen als u expliciete conversiefuncties voor gegevenstypen gebruikt.

  • Impliciete conversie van gegevenstypes kan een negatieve invloed hebben op de prestaties, vooral als het gegevenstype van een kolomwaarde wordt geconverteerd naar een constante in plaats van andersom.

  • Impliciete conversie hangt af van de context waarin deze plaatsvindt en werkt mogelijk niet in alle gevallen op dezelfde manier. Een impliciete conversie van een datetime-waarde naar een VARCHAR2-waarde kan bijvoorbeeld een onverwacht jaar opleveren, afhankelijk van de waarde van de parameter NLS_DATE_FORMAT.

  • Algoritmen voor impliciete conversie kunnen worden gewijzigd tussen softwarereleases en tussen Oracle-producten. Het gedrag van expliciete conversies is voorspelbaarder.

Dat is geen mooie lijst; maar het voorlaatste punt brengt me mooi op daten. Als we de vorige zoekopdracht nemen en deze omzetten in een zoekopdracht die in plaats daarvan een datum gebruikt:

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;

Nogmaals, met DUMP voor deze query retourneren de CASE-instructies gegevenstype 12, een DATE. De DECODE heeft sysdate geconverteerd in een 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

Merk op (in de SQL Fiddle) dat de DATE is omgezet in een teken met behulp van de sessies NLS_DATE_FORMAT.

Het hebben van een datum die impliciet is omgezet in een VARCHAR2 kan problemen veroorzaken. Als je van plan bent TO_CHAR te gebruiken om je datum in een teken om te zetten, zal je zoekopdracht breken waar je hem niet verwacht.

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

Evenzo werkt datumberekening niet meer:

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 is dat DECODE de uitdrukking alleen naar een VARCHAR2 converteert als een van de mogelijke resultaten NULL is. Als de standaardwaarde NULL is, gebeurt dit niet. Bijvoorbeeld:

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

Merk op dat de DECODE een gegevenstype van 13 heeft geretourneerd. Dit is niet gedocumenteerd, maar is, neem ik aan, een type datum, aangezien rekenkunde voor datums enz. werkt.

Kortom, vermijd DECODE indien mogelijk; u krijgt mogelijk niet noodzakelijk de gegevenstypen die u verwacht. Om Tom Kyte te citeren:

Decoderen is enigszins obscuur -- CASE is heel erg duidelijk. Dingen die gemakkelijk te doen zijn bij het decoderen, zijn gemakkelijk te doen in CASE, dingen die moeilijk of bijna onmogelijk zijn om te doen bij het decoderen, zijn gemakkelijk te doen in CASE. CASE wint logischerwijs zonder meer.

Om compleet te zijn zijn er twee functionele verschillen tussen DECODE en CASE.

  1. DECODE kan niet worden gebruikt binnen PL/SQL.
  2. CASE kan niet worden gebruikt om nulls rechtstreeks te vergelijken

    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. Tabel wordt twee keer gespecificeerd, zowel als doel voor 'UPDATE' en als aparte bron voor gegevens in mysql

  2. Wijzig het type kolom met getallen van varchar in int

  3. SQLite LIKE

  4. 5 fouten bij het ontwerpen van databases die u moet vermijden