Использование 'case expression column' в предложении where - PullRequest
22 голосов
/ 01 июля 2011
SELECT ename
  ,    job
  ,    CASE deptno
         WHEN 10
           THEN 'ACCOUNTS'
         WHEN 20
           THEN 'SALES'
         ELSE 'UNKNOWN'
       END AS department
FROM emp /* !!! */ 
WHERE department = 'SALES'

Это не удалось:

ORA-00904: "% s: неверный идентификатор"

Есть ли способ преодолеть это ограничение в Oracle 10.2 SQL? Как использовать «столбец выражения выражения» в предложении where?

Ответы [ 6 ]

40 голосов
/ 01 июля 2011

Причина этой ошибки заключается в том, что операторы SQL SELECT логически * обрабатываются в следующем порядке:

  • FROM: выбор одной таблицы или нескольких объединенных и всех комбинаций строк, соответствующих условиям ON.

  • WHERE:условия оцениваются, и строки, которые не совпадают, удаляются.

  • GROUP BY: строки группируются (и каждая группа сворачивается в одну строку)

  • HAVING: условия оцениваются и удаляются несоответствующие строки.

  • SELECT: оценивается список столбцов.

  • DISTINCT: удаляются дублирующиеся строки (если это оператор SELECT DISTINCT)

  • UNION, EXCEPT, INTERSECT: действие этого операнда выполняется над строками операторов sub-SELECT.Например, если это UNION, все строки собираются (и дубликаты удаляются, если это не UNION ALL) после оценки всех операторов sub-SELECT.Соответственно для случаев ИСКЛЮЧЕНИЯ или ИНТЕРСЕКТА.

  • ORDER BY: строки упорядочены.

Следовательно, вы не можете использовать в предложении WHEREчто-то, что еще не было заполнено или рассчитано.См. Также этот вопрос: oracle-sql-clause -valuation-order

* логически обработано: Обратите внимание, что механизмы базы данных могута также выберите другой порядок оценки для запроса (и это то, что они обычно делают!) Единственное ограничение заключается в том, что результаты должны быть такими же, как если бы использовался вышеуказанный порядок .


Решение состоит в том, чтобы заключить запрос в другой :

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' ;

или продублировать вычисление в условии 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' ;

Полагаю, это упрощенная версия вашего запроса, или вы можете использовать:

SELECT ename
     , job
     , 'SALES' AS department
FROM emp
WHERE deptno = 20 ;
7 голосов
/ 01 июля 2011

Ваша таблица не содержит столбца «отдел», и поэтому вы не можете ссылаться на него в предложении where. Вместо этого используйте deptno.

SELECT ename
,      job
,      CASE deptno
          WHEN 10
          THEN 'ACCOUNTS'
          WHEN 20
          THEN 'SALES'
          ELSE 'UNKNOWN'
       END AS department
FROM   emp /* !!! */ where deptno = 20;
4 голосов
/ 01 июля 2011

Эта работа для меня:

SELECT ename, job
FROM   emp 
WHERE CASE WHEN deptno = 10 THEN 'ACCOUNTS'
           WHEN deptno = 20 THEN 'SALES'
           ELSE 'UNKNOWN'  
      END
      = 'SALES'
1 голос
/ 21 апреля 2013
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';
0 голосов
/ 14 января 2016

Oracle пытается отфильтровать количество записей, которые нужно отсканировать из таблицы, сначала перейдя к предложению where перед выбором, поэтому ваш запрос не выполняется. Более того, ваш запрос никогда не возвращал бы строки с отделом - «Счета или неизвестные» из-за фильтра «Отдел» = «ПРОДАЖИ»

Попробуйте ниже, вместо этого будет легко получить Engine:

ВЫБЕРИТЕ ename, job, отдел 'SALES' AS ОТ emp ГДЕ дептно = 20;

0 голосов
/ 01 июля 2011

попробовать:

  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';
...