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

Un'istruzione CASE e un DECODE sono equivalenti?

Risposta breve, no.

La risposta leggermente più lunga è quasi.

Solo appare che il risultato ottenuto da ciascuna affermazione è identico. Se utilizziamo la funzione DUMP per valutare i tipi di dati restituiti, vedrai cosa intendo:

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 Violino

Puoi vedere che il tipo di dati di DECODE è 1, mentre le due istruzioni CASE "restituiscono" un tipo di dati di 2. Utilizzando il Riepilogo dei tipi di dati di Oracle, DECODE restituisce un VARCHAR2 (tipo di dati 1) mentre le istruzioni CASE "restituiscono " numeri (tipo di dati 2).

Presumo che ciò avvenga perché, come suggeriscono i nomi, DECODE è una funzione e CASE non lo è, il che implica che sono stati implementati internamente in modo diverso. Non esiste un vero modo per dimostrarlo.

Potresti pensare che questo non influisca davvero su nulla. Se hai bisogno che sia un numero, Oracle convertirà implicitamente il carattere in un numero secondo le regole di conversione implicita, giusto? Neanche questo è vero, non funzionerà in un'UNION come i tipi di dati hanno essere identico; Oracle non eseguirà alcuna conversione implicita per semplificarti le cose. In secondo luogo, ecco cosa dice Oracle sulla conversione implicita:

Oracle consiglia di specificare conversioni esplicite, piuttosto che fare affidamento su conversioni implicite o automatiche, per questi motivi:

  • Le istruzioni SQL sono più facili da capire quando si utilizzano funzioni di conversione esplicita del tipo di dati.

  • La conversione implicita del tipo di dati può avere un impatto negativo sulle prestazioni, soprattutto se il tipo di dati di un valore di colonna viene convertito in quello di una costante anziché il contrario.

  • La conversione implicita dipende dal contesto in cui si verifica e potrebbe non funzionare allo stesso modo in ogni caso. Ad esempio, la conversione implicita da un valore datetime a un valore VARCHAR2 può restituire un anno imprevisto a seconda del valore del parametro NLS_DATE_FORMAT.

  • Gli algoritmi per la conversione implicita sono soggetti a modifiche tra le versioni software e tra i prodotti Oracle. Il comportamento delle conversioni esplicite è più prevedibile.

Non è una bella lista; ma il penultimo punto mi porta piacevolmente alle date. Se prendiamo la query precedente e la convertiamo in una che utilizza invece una data:

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;

Ancora una volta, utilizzando DUMP su questa query, le istruzioni CASE restituiscono il tipo di dati 12, una DATE. Il DECODE ha convertito sysdate in un 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 Violino

Nota (in SQL Fiddle) che DATE è stato convertito in un carattere utilizzando le sessioni NLS_DATE_FORMAT.

Avere una data che è stata convertita in modo implicito in un VARCHAR2 può causare problemi. Se intendi utilizzare TO_CHAR, per convertire la tua data in un carattere, la tua query si interromperà dove non te l'aspetti.

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 Violino

Allo stesso modo, l'aritmetica della data non funziona più:

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 Violino

È interessante notare che DECODE converte l'espressione in un VARCHAR2 solo se uno dei possibili risultati è NULL. Se il valore predefinito è NULL, ciò non accade. Ad esempio:

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 Violino

Nota che il DECODE ha restituito un tipo di dati di 13. Questo non è documentato ma è, suppongo, un tipo di data poiché funziona aritmetica della data ecc.

In breve, evita DECODE se possibile; potresti non ottenere necessariamente i tipi di dati che ti aspetti. Per citare Tom Kyte:

La decodifica è alquanto oscura -- CASE è molto, molto chiaro. Le cose che sono facili da fare nella decodifica sono facili da fare in CASE, le cose che sono difficili o quasi impossibili da fare con la decodifica sono facili da fare in CASE. CASE, logicamente, vince a mani basse.

Tanto per essere completi ce ne sono due funzionali differenze tra DECODE e CASE.

  1. DECODE non può essere utilizzato in PL/SQL.
  2. CASE non può essere utilizzato per confrontare direttamente i valori null

    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 Violino