Oracle
 sql >> Base de données >  >> RDS >> Oracle

Une instruction CASE et un DECODE sont-ils équivalents ?

Réponse courte, non.

La réponse légèrement plus longue est presque.

Il apparaît seulement que le résultat obtenu à partir de chaque instruction est identique. Si nous utilisons la fonction DUMP pour évaluer les types de données renvoyés, vous verrez ce que je veux dire :

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

Violon SQL

Vous pouvez voir que le type de données de DECODE est 1, alors que les deux instructions CASE « renvoient » un type de données de 2. En utilisant le résumé des types de données d'Oracle, DECODE renvoie un VARCHAR2 (type de données 1) alors que les instructions CASE « renvoient " nombres (type de données 2).

Je suppose que cela se produit parce que, comme les noms le suggèrent, DECODE est une fonction et CASE ne l'est pas, ce qui implique qu'ils ont été implémentés différemment en interne. Il n'y a aucun moyen réel de le prouver.

Vous pourriez penser que cela n'affecte vraiment rien. Si vous avez besoin que ce soit un nombre, Oracle convertira implicitement le caractère en un nombre selon les règles de conversion implicites, n'est-ce pas ? Ce n'est pas vrai non plus, cela ne fonctionnera pas dans une UNION car les types de données ont être identique; Oracle ne fera aucune conversion implicite pour vous faciliter la tâche. Deuxièmement, voici ce que dit Oracle à propos de la conversion implicite :

Oracle vous recommande de spécifier des conversions explicites, plutôt que de vous fier à des conversions implicites ou automatiques, pour les raisons suivantes :

  • Les instructions SQL sont plus faciles à comprendre lorsque vous utilisez des fonctions de conversion de type de données explicites.

  • La conversion implicite du type de données peut avoir un impact négatif sur les performances, en particulier si le type de données d'une valeur de colonne est converti en celui d'une constante plutôt que l'inverse.

  • La conversion implicite dépend du contexte dans lequel elle se produit et peut ne pas fonctionner de la même manière dans tous les cas. Par exemple, la conversion implicite d'une valeur datetime en une valeur VARCHAR2 peut renvoyer une année inattendue en fonction de la valeur du paramètre NLS_DATE_FORMAT.

  • Les algorithmes de conversion implicite sont susceptibles de changer d'une version de logiciel à l'autre et d'un produit Oracle à l'autre. Le comportement des conversions explicites est plus prévisible.

Ce n'est pas une jolie liste; mais l'avant-dernier point m'amène bien aux dates. Si nous prenons la requête précédente et la convertissons en une qui utilise une date à la place :

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;

Encore une fois, en utilisant DUMP sur cette requête, les instructions CASE renvoient le type de données 12, une DATE. Le DECODE a converti sysdate dans 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

Violon SQL

Notez (dans le SQL Fiddle) que la DATE a été convertie en caractère à l'aide des sessions NLS_DATE_FORMAT.

Avoir une date implicitement convertie en VARCHAR2 peut causer des problèmes. Si vous avez l'intention d'utiliser TO_CHAR, pour convertir votre date en caractère, votre requête se cassera là où vous ne l'attendez pas.

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

Violon SQL

De même, l'arithmétique des dates ne fonctionne plus :

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

Violon SQL

Fait intéressant, DECODE ne convertit l'expression en VARCHAR2 que si l'un des résultats possibles est NULL. Si la valeur par défaut est NULL, cela ne se produit pas. Par exemple :

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

Violon SQL

Notez que DECODE a renvoyé un type de données de 13. Ce n'est pas documenté mais c'est, je suppose, un type de date car l'arithmétique de date, etc. fonctionne.

En bref, évitez DECODE si vous le pouvez; vous n'obtiendrez peut-être pas nécessairement les types de données que vous attendez. Pour citer Tom Kyte :

Le décodage est quelque peu obscur -- CASE est très très clair. Les choses faciles à faire dans le décodage sont faciles à faire dans CASE, les choses difficiles ou presque impossibles à faire avec le décodage sont faciles à faire dans CASE. CASE, logiquement, gagne haut la main.

Juste pour être complet, il y a deux éléments fonctionnels différences entre DECODE et CASE.

  1. DECODE ne peut pas être utilisé dans PL/SQL.
  2. CASE ne peut pas être utilisé pour comparer directement les valeurs nulles

    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
    

    Violon SQL