web-dev-qa-db-fra.com

Utilisation de 'case expression column' dans la clause where

SELECT ename
  ,    job
  ,    CASE deptno
         WHEN 10
           THEN 'ACCOUNTS'
         WHEN 20
           THEN 'SALES'
         ELSE 'UNKNOWN'
       END AS department
FROM emp /* !!! */ 
WHERE department = 'SALES'

Cela échoue:

ORA-00904: "% s: identificateur non valide" 

Existe-t-il un moyen de surmonter cette limitation dans Oracle 10.2 SQL? Comment utiliser la 'colonne d'expression de cas' dans la clause where?

21
EugeneP

La raison de cette erreur est que les instructions SQL SELECT sont logiquement * traitées dans l'ordre suivant:

  • FROM: sélection d'une table ou de plusieurs tables JOINNELLES et de toutes les combinaisons de lignes correspondant aux conditions ON.

  • WHERE: les conditions sont évaluées et les lignes qui ne correspondent pas sont supprimées.

  • GROUP BY: les lignes sont groupées (et chaque groupe se réduit à une ligne)

  • HAVING: les conditions sont évaluées et les lignes qui ne correspondent pas sont supprimées.

  • SELECT: la liste des colonnes est évaluée.

  • DISTINCT: les lignes en double sont supprimées (s'il s'agit d'une instruction SELECT DISTINCT)

  • (UNION, EXCEPT, INTERSECT: l'action de cet opérande est exécutée sur les lignes des instructions sous-SELECT. Par exemple, s'il s'agit d'un UNION, toutes les lignes sont rassemblées (et les doublons éliminés, sauf s'il s'agit d'un UNION ALL) une fois que toutes les instructions sous-SELECT ont été évaluées. En conséquence pour les cas EXCEPT ou INTERSECT. 

  • ORDER BY: les lignes sont ordonnées.

Par conséquent, vous ne pouvez pas utiliser dans la clause WHERE, quelque chose qui n'a pas encore été rempli ou calculé. Voir aussi cette question: Oracle-sql-clause-evaluation-order

* logiquement traité: Notez que les moteurs de base de données peuvent également choisir un autre ordre d'évaluation pour une requête (et c'est ce qu'ils font habituellement!). La seule restriction est que le les résultats doivent être les mêmes que si l'ordre précédent était utilisé .


La solution est de inclure la requête dans une autre:

SELECT *
FROM
  ( SELECT ename
         , job
         , CASE deptno
             WHEN 10 THEN 'ACCOUNTS'
             WHEN 20 THEN 'SALES'
                     ELSE 'UNKNOWN'
           END AS department
    FROM emp
  ) tmp
WHERE department = 'SALES' ;

ou to dupliquer le calcul dans la condition WHERE:

SELECT ename
     , job
     , CASE deptno
         WHEN 10 THEN 'ACCOUNTS'
         WHEN 20 THEN 'SALES'
                 ELSE 'UNKNOWN'
       END AS department
FROM emp
WHERE
    CASE deptno
      WHEN 10 THEN 'ACCOUNTS'
      WHEN 20 THEN 'SALES'
              ELSE 'UNKNOWN'
    END = 'SALES' ;

Je suppose que ceci est une version simplifiée de votre requête ou vous pourriez utiliser:

SELECT ename
     , job
     , 'SALES' AS department
FROM emp
WHERE deptno = 20 ;
39
ypercubeᵀᴹ

Votre table ne contient pas de colonne "department" et vous ne pouvez donc pas la référencer dans votre clause where. Utilisez deptno à la place.

SELECT ename
,      job
,      CASE deptno
          WHEN 10
          THEN 'ACCOUNTS'
          WHEN 20
          THEN 'SALES'
          ELSE 'UNKNOWN'
       END AS department
FROM   emp /* !!! */ where deptno = 20;
7
Martin Schapendonk

Ce travail pour moi:

SELECT ename, job
FROM   emp 
WHERE CASE WHEN deptno = 10 THEN 'ACCOUNTS'
           WHEN deptno = 20 THEN 'SALES'
           ELSE 'UNKNOWN'  
      END
      = 'SALES'
4
Cyril Gandon
select emp_.*
from (SELECT ename
  ,    job
  ,    CASE deptno
         WHEN 10
           THEN 'ACCOUNTS'
         WHEN 20
           THEN 'SALES'
         ELSE 'UNKNOWN'
       END AS department
FROM emp /* !!! */ ) emp_ where emp_.department='UNKNOWN';
1
Amitābha

essayer:

  SQL> SELECT ename
      2  ,      job
      3  ,      CASE
      4            WHEN  deptno = 10
      5            THEN 'ACCOUNTS'
      6            WHEN  deptno = 20
      7            THEN 'SALES'
     12            ELSE 'UNKNOWN'
     13         END AS department
     14  FROM   emp /* !!! */ where department = 'SALES';
0
marchaos

Oracle essaie de filtrer le nombre d'enregistrements à analyser à partir d'une table en recherchant d'abord la clause where avant de sélectionner, raison pour laquelle votre requête échoue. De plus, votre requête n'aurait jamais renvoyé de lignes avec le service - "Comptes ou Inconnu" en raison du filtre Department = "VENTES".

Essayez ci-dessous, cela sera facile à récupérer par le moteur:

SELECT ename, job, 'VENTES' AS département DE emp WHERE deptno = 20;

0
Himansh Gautam