Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Sind eine CASE-Anweisung und eine DECODE-Anweisung äquivalent?

Kurze Antwort, nein.

Die etwas längere Antwort ist fast.

Es erscheint nur dass das Ergebnis jeder Anweisung identisch ist. Wenn wir die DUMP-Funktion verwenden, um die zurückgegebenen Datentypen auszuwerten, werden Sie sehen, was ich meine:

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

Sie können sehen, dass der Datentyp von DECODE 1 ist, während die beiden CASE-Anweisungen einen Datentyp von 2 "zurückgeben". Unter Verwendung von Oracles Data Type Summary gibt DECODE ein VARCHAR2 (Datentyp 1) zurück, während die CASE-Anweisungen "zurückgeben". " Zahlen (Datentyp 2).

Ich nehme an, dass dies geschieht, weil DECODE, wie der Name schon sagt, eine Funktion ist und CASE ist es nicht, was impliziert, dass sie intern anders implementiert wurden. Es gibt keine wirkliche Möglichkeit, dies zu beweisen.

Sie könnten denken, dass dies nicht wirklich etwas beeinflusst. Wenn Sie eine Zahl benötigen, konvertiert Oracle das Zeichen implizit in eine Zahl gemäß den impliziten Konvertierungsregeln, richtig? Das stimmt auch nicht, es funktioniert nicht in einer UNION wie die Datentypen haben identisch sein; Oracle führt keine implizite Konvertierung durch, um Ihnen die Arbeit zu erleichtern. Zweitens sagt Oracle Folgendes über die implizite Konvertierung:

Oracle empfiehlt aus folgenden Gründen, dass Sie explizite Konvertierungen angeben, anstatt sich auf implizite oder automatische Konvertierungen zu verlassen:

  • SQL-Anweisungen sind leichter verständlich, wenn Sie explizite Datentyp-Konvertierungsfunktionen verwenden.

  • Die implizite Datentypkonvertierung kann sich negativ auf die Leistung auswirken, insbesondere wenn der Datentyp eines Spaltenwerts in den einer Konstanten konvertiert wird und nicht umgekehrt.

  • Die implizite Konvertierung hängt vom Kontext ab, in dem sie auftritt, und funktioniert möglicherweise nicht in jedem Fall auf die gleiche Weise. Beispielsweise kann die implizite Konvertierung von einem datetime-Wert in einen VARCHAR2-Wert abhängig vom Wert des Parameters NLS_DATE_FORMAT ein unerwartetes Jahr zurückgeben.

  • Algorithmen für die implizite Konvertierung können sich über Softwareversionen und zwischen Oracle-Produkten hinweg ändern. Das Verhalten expliziter Conversions ist vorhersehbarer.

Das ist keine schöne Liste; aber der vorletzte punkt bringt mich schön auf daten. Wenn wir die vorherige Abfrage nehmen und sie in eine umwandeln, die stattdessen ein Datum verwendet:

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;

Auch hier geben die CASE-Anweisungen bei Verwendung von DUMP bei dieser Abfrage den Datentyp 12, ein DATUM, zurück. Der DECODE hat sysdate konvertiert in ein 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

Beachten Sie (in der SQL-Fiddle), dass das DATE mithilfe der Sitzungen NLS_DATE_FORMAT.

in ein Zeichen umgewandelt wurde

Ein Datum, das implizit in ein VARCHAR2 konvertiert wurde, kann Probleme verursachen. Wenn Sie beabsichtigen, TO_CHAR zu verwenden, um Ihr Datum in ein Zeichen umzuwandeln, bricht Ihre Abfrage dort ab, wo Sie es nicht erwarten.

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

Ebenso funktioniert die Datumsarithmetik nicht mehr:

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

Interessanterweise konvertiert DECODE den Ausdruck nur dann in ein VARCHAR2, wenn eines der möglichen Ergebnisse NULL ist. Wenn der Standardwert NULL ist, passiert dies nicht. Zum Beispiel:

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

Beachten Sie, dass DECODE einen Datentyp von 13 zurückgegeben hat. Dies ist nicht dokumentiert, aber ich nehme an, dass es sich um einen Datumstyp handelt, da Datumsarithmetik usw. funktioniert.

Kurz gesagt, vermeiden Sie DECODE, wenn Sie können; Möglicherweise erhalten Sie nicht unbedingt die erwarteten Datentypen. Um Tom Kyte zu zitieren:

Die Dekodierung ist etwas unklar – CASE ist sehr, sehr klar. Dinge, die beim Decodieren einfach zu tun sind, sind in CASE einfach zu tun, Dinge, die beim Decodieren schwer oder fast unmöglich zu tun sind, sind in CASE einfach zu tun. CASE gewinnt logischerweise zweifellos.

Der Vollständigkeit halber gibt es zwei funktionale Unterschiede zwischen DECODE und CASE.

  1. DECODE kann nicht innerhalb von PL/SQL verwendet werden.
  2. CASE kann nicht verwendet werden, um Nullen direkt zu vergleichen

    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