sql >> Base de Datos >  >> RDS >> Oracle

¿Son equivalentes una sentencia CASE y una DECODE?

Respuesta corta, no.

La respuesta un poco más larga es casi.

Solo aparece que el resultado obtenido de cada afirmación es idéntico. Si usamos la función DUMP para evaluar los tipos de datos devueltos, verá lo que quiero decir:

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

Violín SQL

Puede ver que el tipo de datos de DECODE es 1, mientras que las dos instrucciones CASE "devuelven" un tipo de datos de 2. Usando el resumen de tipos de datos de Oracle, DECODE devuelve un VARCHAR2 (tipo de datos 1) mientras que las declaraciones CASE "devuelven" " números (tipo de datos 2).

Supongo que esto ocurre porque, como sugieren los nombres, DECODE es una función y CASE no lo es, lo que implica que se han implementado de manera diferente internamente. No hay una forma real de probar esto.

Se podría pensar que esto realmente no afecta nada. Si necesita que sea un número, Oracle convertirá implícitamente el carácter en un número según las reglas de conversión implícitas, ¿verdad? Esto tampoco es cierto, no funcionará en UNION ya que los tipos de datos tienen ser idéntico; Oracle no realizará ninguna conversión implícita para facilitarle las cosas. En segundo lugar, esto es lo que dice Oracle sobre la conversión implícita:

Oracle recomienda que especifique conversiones explícitas, en lugar de basarse en conversiones implícitas o automáticas, por los siguientes motivos:

  • Las declaraciones SQL son más fáciles de entender cuando utiliza funciones de conversión de tipos de datos explícitos.

  • La conversión implícita de tipos de datos puede tener un impacto negativo en el rendimiento, especialmente si el tipo de datos de un valor de columna se convierte en una constante y no al revés.

  • La conversión implícita depende del contexto en el que se produce y es posible que no funcione de la misma manera en todos los casos. Por ejemplo, la conversión implícita de un valor de fecha y hora a un valor VARCHAR2 puede devolver un año inesperado según el valor del parámetro NLS_DATE_FORMAT.

  • Los algoritmos para la conversión implícita están sujetos a cambios entre las versiones de software y entre los productos de Oracle. El comportamiento de las conversiones explícitas es más predecible.

Esa no es una lista bonita; pero el penúltimo punto me lleva muy bien a las fechas. Si tomamos la consulta anterior y la convertimos en una que use una fecha en su lugar:

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;

Una vez más, al usar DUMP en esta consulta, las declaraciones CASE devuelven el tipo de datos 12, una FECHA. El DECODE ha convertido sysdate en 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

Violín SQL

Tenga en cuenta (en SQL Fiddle) que la FECHA se ha convertido en un carácter usando las sesiones NLS_DATE_FORMAT.

Tener una fecha que se haya convertido implícitamente en un VARCHAR2 puede causar problemas. Si tiene la intención de usar TO_CHAR, para convertir su fecha en un carácter, su consulta se romperá donde no la espera.

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

Violín SQL

Igualmente, la aritmética de fechas ya no funciona:

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

Violín SQL

Curiosamente, DECODE solo convierte la expresión en VARCHAR2 si uno de los posibles resultados es NULL. Si el valor predeterminado es NULL, esto no sucede. Por ejemplo:

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

Violín SQL

Tenga en cuenta que DECODE ha devuelto un tipo de datos de 13. Esto no está documentado, pero supongo que es un tipo de fecha como funciona la aritmética de fechas, etc.

En resumen, evite DECODE si es posible; es posible que no obtenga necesariamente los tipos de datos que espera. Para citar a Tom Kyte:

La decodificación es algo oscura; CASE es muy, muy claro. Las cosas que son fáciles de hacer en decodificación son fáciles de hacer en CASE, las cosas que son difíciles o casi imposibles de hacer con decodificación son fáciles de hacer en CASE. CASE, lógicamente, gana sin duda alguna.

Para completar, hay dos funcionales diferencias entre DECODE y CASE.

  1. DECODE no se puede usar dentro de PL/SQL.
  2. CASE no se puede usar para comparar nulos directamente

    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
    

    Violín SQL