2015-08-07 3 views
0

У меня есть следующий запрос в базе данных AdventureWorks2012Когда вычисляется оператор CASE?

SELECT productid, 
     productname, 
     unitprice, 
     CASE 
      WHEN unitprice < 20.0 THEN 'LOW' 
      WHEN unitprice < 40.0 THEN 'MEDIUM' 
      WHEN unitprice >= 40.0 THEN 'HIGH' 
     END pricerange 
FROM Production.Products 
ORDER BY 
    CASE 
     WHEN pricerange < 'LOW' THEN 1 
     WHEN pricerange < 'MEDIUM' THEN 2 
     WHEN pricerange >= 'HIGH' THEN 3 
    END ASC 
GO 

ORDER BY происходит после SELECT заявления, но имя столбца pricerange не может быть доступен? Я предполагаю, что pricerange в операторе SELECT рассчитывается после того, как вызывается ORDER BY? Почему это?

+1

Вы уверены, что это действительно работает? Я почти уверен, что это не помогло, хотя некоторые версии SQL Server, возможно, допустили это. Какую версию SQL Server вы используете? В любом случае то, что и когда рассчитывается, не ясны в SQL - это декларативный язык, а не императивный, поэтому порядок выполнения не фиксирован. Механизм выполнения определяет лучший способ выполнения запроса (вы можете включить план выполнения, чтобы проверить его). – Luaan

+0

@ Luaan это не работает, вот почему я его спросил :) – ProgrammerAtWork

+0

Может быть, имя столбца 'pricerange' неоднозначно? Возможно, в таблице 'Products' уже есть столбец' pricerange'? – Luaan

ответ

3

SQL - это декларативный язык, а не императивный. Порядок выполнения не определен, и это не всегда одно и то же.

В любом случае, порядок исполнения не имеет особого значения. Основной момент заключается в том, что область область - и pricerange не находится в области действия внутри этого оператора select. Вместо того, чтобы думать о порядке, в котором появляются строки кода (как в императивном программировании), вы должны подумать о том, как каждое выражение обертывает другое выражение.

В этом случае, вы делаете что-то вроде этого:

Select(OrderBy(From(Products), ...), ...) 

У вас есть два пути вокруг этого - один вариант использовать тот же самый случай, в порядке, как тот, который вы используете в избранных (не волнуйтесь, двигатель достаточно умен, чтобы не выполнять работу дважды). Во-вторых, чтобы обернуть ваш запрос в другой запрос, который делает фактический порядок:

select * from 
(
    SELECT productid, 
      productname, 
      unitprice, 
      CASE 
       WHEN unitprice < 20.0 THEN 'LOW' 
       WHEN unitprice < 40.0 THEN 'MEDIUM' 
       WHEN unitprice >= 40.0 THEN 'HIGH' 
      END pricerange 
    FROM Production.Products 
) 
ORDER BY 
    CASE 
     WHEN pricerange < 'LOW' THEN 1 
     WHEN pricerange < 'MEDIUM' THEN 2 
     WHEN pricerange >= 'HIGH' THEN 3 
    END ASC 

Но имейте в виду, что вы имеете дело с деревьев выражений здесь, не командует списки. Вы описываете, что хотите, а не , как он собирается выполнить. как - это работа механизма выполнения.

В конце концов, механизм выполнения может выполнить один и тот же план выполнения для обоих вариантов запроса - они не совсем разные; хотя, например, могут быть некоторые угловые случаи вокруг NULL, я не уверен.

+0

Что вы думаете о том, что я делаю 'Select (OrderBy (From (Products), ...), ...)' вместо 'OrderBy (Select (From (Products), ...),. ..) '? – ProgrammerAtWork

+0

@ProgrammerAtWork Потому что это то, что говорит ваш код. SQL не является обязательным - он не оценивается в порядке написания (хотя некоторые двигатели приближаются, чем другие - Oracle, например, нуждается в упорядоченных объединениях). В одном выражении select выражение 'select' само оценивается почти последним (это всего лишь сопоставление значений результата). Интересно, что в документации говорится, что «порядок» должен иметь результаты выбора - по моему опыту, который никогда не был так. Возможно, использование индекса столбца вместо имени столбца будет работать, но это очень хрупкое. – Luaan

+0

@ProgrammerAtWork Aha! Это действительно новая функция. Вот почему документация, похоже, не подходит. Если вы хотите, чтобы это работало, установите базу данных на уровень совместимости для MS SQL 2012 и используйте SQL Server 2012. В противном случае вам нужно убедиться, что порядок не указан * не указывает ссылку на список. – Luaan

3

SQL Server объясняет логический порядок обработки запросов в documentation.

  1. ОТ
  2. ПО
  3. РЕГИСТРИРУЙТЕСЬ
  4. ГДЕ
  5. ГРУППА ПО
  6. С CUBE или ROLLUP С
  7. HAVING
  8. ВЫБОР
  9. DISTINCT
  10. ORDER BY
  11. ТОП

Заметим, что это логично . На практике это означает, что упорядочение используется во время фазы компиляции запроса в основном для определения ссылок на названия.Также обратите внимание, что список представляет собой странную смесь ключевых слов и предложений (ON, WITH, DISTINCT и TOP - это не SQL-предложения).

Что касается вашего запроса, определение pricerange определяется логикой в ​​SELECT. Затем это дополнительно используется в ORDER BY, чтобы получить желаемый заказ. Это логическое описание обработки.

На практике я ожидаю, что SQL Server будет вычислять как pricerange, так и приоритет упорядочивания при проверке данных (SQL Server оптимизирует такие вычисления, выполняя их при чтении данных). Расчет pricerange переходит в окончательный набор результатов. Элемент заказа используется только ORDER BY.

+0

Я вижу, line 'Обратите внимание, что фактическое физическое выполнение оператора определяется процессором запросов, и порядок может отличаться от этого списка. 'в документации говорит так же. Однако в документации также четко сказано, что я могу ссылаться на псевдонимы «SELECT» с «ORDER BY». Какой процесс мышления вы использовали, чтобы определить, что это не так? Как я могу заранее знать, что мой запрос не сработает? Сложные знания о том, как работает процессор запросов, или есть другой способ? – ProgrammerAtWork

+0

@ProgrammerAtWork Это странно. Возможно, документация просто ошибается, это случается раз в то время.Или он только позволяет вам ссылаться на столбцы по их индексу или требует, чтобы вы использовали какой-то специальный псевдоним, я не уверен, но я никогда не видел, чтобы 'order by' использовал столбец из' select' mapping в это же заявление. Но даже документация ORDER BY явно говорит: 'Названия столбцов, на которые ссылается в предложении ORDER BY, должны соответствовать либо столбцу в списке выбора, либо столбцу, определенному в таблице, указанной в предложении FROM, без каких-либо двусмысленностей. '. Weird. – Luaan

Смежные вопросы