sql >> Databáze >  >> RDS >> Oracle

Jsou příkazy CASE a DECODE ekvivalentní?

Krátká odpověď, ne.

Trochu delší odpověď je skoro.

Pouze se zobrazí že výsledek získaný z každého výroku je totožný. Pokud použijeme funkci DUMP k vyhodnocení vrácených datových typů, uvidíte, co tím myslím:

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

Můžete vidět, že datový typ DECODE je 1, zatímco dva příkazy CASE „vrací“ datový typ 2. Pomocí Oracle Data Type Summary vrací DECODE VARCHAR2 (datový typ 1), zatímco příkazy CASE „vrací“ "čísla (datový typ 2).

Předpokládám, že k tomu dochází, protože, jak názvy napovídají, DECODE je funkce a CASE není, což znamená, že byly interně implementovány odlišně. Neexistuje žádný skutečný způsob, jak to dokázat.

Možná si myslíte, že to vlastně nic neovlivňuje. Pokud potřebujete, aby to bylo číslo, Oracle implicitně převede znak na číslo podle implicitních pravidel převodu, že? To také není pravda, nebude to fungovat v UNION, protože datové typy mají být identický; Oracle neprovede žádnou implicitní konverzi, aby vám věci usnadnil. Za druhé, zde je to, co Oracle říká o implicitní konverzi:

Společnost Oracle doporučuje zadat explicitní převody, spíše než spoléhat na implicitní nebo automatické převody, a to z těchto důvodů:

  • Příkazy SQL jsou snáze pochopitelné, když používáte explicitní funkce převodu datových typů.

  • Implicitní převod datového typu může mít negativní dopad na výkon, zvláště pokud je datový typ hodnoty sloupce převeden na konstantu a nikoli naopak.

  • Implicitní převod závisí na kontextu, ve kterém k němu dochází, a nemusí ve všech případech fungovat stejně. Například implicitní převod z hodnoty datetime na hodnotu VARCHAR2 může vrátit neočekávaný rok v závislosti na hodnotě parametru NLS_DATE_FORMAT.

  • Algoritmy pro implicitní převod podléhají změnám v různých verzích softwaru a mezi produkty Oracle. Chování explicitních konverzí je předvídatelnější.

To není hezký seznam; ale předposlední bod mě pěkně přivádí k datům. Pokud vezmeme předchozí dotaz a převedeme ho na dotaz, který místo toho používá datum:

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;

Ještě jednou, pomocí DUMP na tento dotaz vrátí příkazy CASE datový typ 12, DATE. DECODE převedl sysdate do 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

Všimněte si (v SQL Fiddle), že DATE bylo převedeno na znak pomocí relací NLS_DATE_FORMAT.

Datum, které bylo implicitně převedeno na VARCHAR2, může způsobit problémy. Pokud máte v úmyslu použít TO_CHAR k převodu data na znak, váš dotaz se zlomí tam, kde to neočekáváte.

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

Stejně tak již nefunguje aritmetika data:

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

Zajímavé je, že DECODE převede výraz na VARCHAR2 pouze v případě, že jeden z možných výsledků je NULL. Pokud je výchozí hodnota NULL, pak se to nestane. Například:

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

Všimněte si, že DECODE vrátil datový typ 13. Toto není zdokumentováno, ale předpokládám, že jde o typ data, jak funguje aritmetika data atd.

Stručně řečeno, vyhněte se DECODE, pokud je to možné; nemusíte nutně získat datové typy, které očekáváte. Abych citoval Toma Kytea:

Dekódování je poněkud nejasné -- CASE je velmi jasné. Věci, které je snadné dělat v dekódování, se snadno dělají v CASE, věci, které je těžké nebo téměř nemožné dělat s dekódováním, se snadno dělají v CASE. CASE logicky vyhrává.

Pro úplnost jsou dvě funkční rozdíly mezi DECODE a CASE.

  1. DECODE nelze použít v PL/SQL.
  2. CASE nelze použít k přímému porovnání hodnot 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 Fiddle



  1. 3 způsoby, jak zpřístupnit kolace v MariaDB

  2. Mohu slepě nahradit všechny funkce mysql_ funkcí mysqli_?

  3. SUBDATE() vs DATE_SUB() v MySQL:Jaký je rozdíl?

  4. Převzít hodnotu z FieldA, odeslat do funkce db, vrátit hodnotu do FieldB