Oracle
 sql >> база данни >  >> RDS >> Oracle

Еквивалентни ли са изразът CASE и DECODE?

Кратък отговор, не.

Малко по-дългият отговор е почти.

Само появява се че резултатът, получен от всяко твърдение, е идентичен. Ако използваме функцията DUMP за оценка на върнатите типове данни, ще видите какво имам предвид:

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

Можете да видите, че типът данни на DECODE е 1, докато двата оператора CASE "връщат" тип данни от 2. Използвайки обобщението на типа данни на Oracle, DECODE връща VARCHAR2 (тип данни 1), докато операторите CASE се "връщат " числа (тип данни 2).

Предполагам, че това се случва, защото, както подсказват имената, DECODE е функция а CASE не е, което предполага, че са внедрени по различен начин вътрешно. Няма реален начин да се докаже това.

Може да си помислите, че това всъщност не засяга нищо. Ако трябва да е число, Oracle ще преобразува имплицитно знака в число съгласно правилата за имплицитно преобразуване, нали? Това също не е вярно, няма да работи в UNION, тъй като типовете данни имат да бъдат идентични; Oracle няма да направи никакво имплицитно преобразуване, за да улесни нещата за вас. Второ, ето какво казва Oracle за имплицитното преобразуване:

Oracle препоръчва да посочите изрични преобразувания, вместо да разчитате на имплицитни или автоматични преобразувания, поради следните причини:

  • SQL изразите са по-лесни за разбиране, когато използвате функции за изрично преобразуване на тип данни.

  • Неявното преобразуване на тип данни може да има отрицателно въздействие върху производителността, особено ако типът данни на стойност на колона се преобразува в този на константа, а не обратното.

  • Неявното преобразуване зависи от контекста, в който се случва и може да не работи по същия начин във всеки случай. Например, неявното преобразуване от стойност на дата и час към стойност VARCHAR2 може да върне неочаквана година в зависимост от стойността на параметъра NLS_DATE_FORMAT.

  • Алгоритмите за имплицитно преобразуване подлежат на промяна в различните версии на софтуера и между продуктите на Oracle. Поведението на изричните преобразувания е по-предвидимо.

Това не е хубав списък; но предпоследната точка ме насочва добре към датите. Ако вземем предишната заявка и я преобразуваме в такава, която вместо това използва дата:

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;

Още веднъж, използвайки DUMP за тази заявка, операторите CASE връщат тип данни 12, DATE. DECODE преобразува sysdate във 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

Обърнете внимание (в SQL Fiddle), че DATE е преобразуван в знак с помощта на сесиите NLS_DATE_FORMAT.

Наличието на дата, която е имплицитно преобразувана в VARCHAR2, може да причини проблеми. Ако възнамерявате да използвате TO_CHAR, за да преобразувате датата си в знак, вашата заявка ще се счупи там, където не го очаквате.

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

По същия начин аритметиката по дата вече не работи:

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

Интересното е, че DECODE преобразува израза в VARCHAR2 само ако един от възможните резултати е NULL. Ако стойността по подразбиране е NULL, това не се случва. Например:

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

Обърнете внимание, че DECODE е върнал тип данни от 13. Това не е документирано, но предполагам, че е тип дата, тъй като аритметиката за дата и т.н. работи.

Накратко, избягвайте DECODE, ако е възможно; може да не получите непременно типовете данни, които очаквате. Да цитирам Том Кайт:

Декодирането е малко неясно - CASE е много, много ясен. Нещата, които са лесни за правене при декодиране, са лесни за правене в CASE, нещата, които са трудни или почти невъзможни за декодиране, са лесни за правене в CASE. CASE, логически, печели ръцете.

Само за да бъдем завършени, има две функционални разлики между DECODE и CASE.

  1. DECODE не може да се използва в рамките на PL/SQL.
  2. CASE не може да се използва за директно сравняване на нули

    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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Достъп до уеб услугата от съхранената процедура на Oracle

  2. Каква е максималната дължина на името на таблица в Oracle?

  3. Трябва ли да създавам индекси на външни ключове на Oracle?

  4. ORA-01017 Невалидно потребителско име/парола при свързване към 11g база данни от 9i клиент

  5. Как да промените уеб порта в EBS 12.2