SQL Server 2008 - операторы Case / If в предложении SELECT

У меня есть запрос, который должен работать вот так -


If(var = xyz) 
   SELECT col1, col2
ELSE IF(var = zyx)
   SELECT col2, col3
ELSE
   SELECT col7,col8

FROM 

.
.
.

Как добиться этого в T-SQL без написания отдельных запросов для каждого предложения? В настоящее время я использую его как


IF (var = xyz) {
  Query1
}
ELSE IF (var = zyx) {
  Query2
}
ELSE {
  Query3
}

Это просто много избыточного кода для выбора разных столбцов в зависимости от значения. Есть альтернативы?


person Tejaswi Yerukalapudi    schedule 13.07.2009    source источник


Ответы (6)


Просто обратите внимание, что вам может быть лучше иметь 3 отдельных SELECTS по причинам оптимизации. Если у вас есть один единственный SELECT, тогда сгенерированный план должен будет проецировать все столбцы col1, col2, col3, col7, col8 и т. Д., Хотя, в зависимости от значения времени выполнения @var, необходимы только некоторые. Это может привести к планам, которые выполняют ненужный поиск по кластеризованному индексу, поскольку некластеризованный индекс не охватывает все столбцы, спроецированные с помощью SELECT.

С другой стороны, 3 отдельных SELECTS, каждый из которых проецирует только необходимые столбцы, могут выиграть от некластеризованных индексов, которые охватывают только ваш прогнозируемый столбец в каждом случае.

Конечно, это зависит от фактической схемы вашей модели данных и точных запросов, но это всего лишь предупреждение, чтобы вы не привносили императивное мышление процедурного программирования в декларативный мир SQL.

person Remus Rusanu    schedule 14.07.2009
comment
+1 очень хорошее наблюдение - person Sam Saffron; 14.07.2009

Вы ищете оператор CASE

http://msdn.microsoft.com/en-us/library/ms181765.aspx

Пример скопирован из MSDN:

USE AdventureWorks;
GO
SELECT   ProductNumber, Category =
      CASE ProductLine
         WHEN 'R' THEN 'Road'
         WHEN 'M' THEN 'Mountain'
         WHEN 'T' THEN 'Touring'
         WHEN 'S' THEN 'Other sale items'
         ELSE 'Not for sale'
      END,
   Name
FROM Production.Product
ORDER BY ProductNumber;
GO
person Sam Saffron    schedule 13.07.2009
comment
Похоже, я был ниндзя! :) - person Jeffrey Hantin; 14.07.2009
comment
Я все еще новичок, поэтому могу (легко) ошибаться, но я думаю, что это на самом деле не отвечает на вопрос, верно? OP спросил, как он может выбрать несколько столбцов, а не назначать один из нескольких вариантов значений одному столбцу, что, похоже, это (и несколько ответов) делает. Если бы я был ОП, казалось бы, ответ от @JoelMansford является наиболее правильным. Пожалуйста, дайте мне знать, если / почему я ошибаюсь, если я ошибаюсь! - person dah97765; 01.10.2013

Попробуйте что-нибудь вроде

SELECT
    CASE var
        WHEN xyz THEN col1
        WHEN zyx THEN col2
        ELSE col7
    END AS col1,
    ...

Другими словами, используйте условное выражение для выбора значения, а затем переименуйте столбец.

В качестве альтернативы вы можете создать какой-нибудь динамический SQL-хак для совместного использования хвоста запроса; Я делал это с iBatis раньше.

person Jeffrey Hantin    schedule 13.07.2009

Простое выражение CASE:

CASE input_expression 
     WHEN when_expression THEN result_expression [ ...n ] 
     [ ELSE else_result_expression ] 
END

Искомое выражение CASE:

CASE
     WHEN Boolean_expression THEN result_expression [ ...n ] 
     [ ELSE else_result_expression ] 
END

Ссылка: http://msdn.microsoft.com/en-us/library/ms181765.aspx

person Sutirth    schedule 16.11.2011

CASE - это ответ, но вам понадобится отдельный оператор case для каждого столбца, который вы хотите вернуть. Пока предложение WHERE остается тем же, не будет особой пользы от разделения его на несколько запросов.

Пример:

SELECT
    CASE @var
        WHEN 'xyz' THEN col1
        WHEN 'zyx' THEN col2
        ELSE col7
    END,
    CASE @var
        WHEN 'xyz' THEN col2
        WHEN 'zyx' THEN col3
        ELSE col8
    END
FROM Table
...
person Rob Boek    schedule 14.07.2009

Наиболее очевидные решения уже перечислены. В зависимости от того, где находится запрос (то есть в коде приложения), вы не всегда можете использовать операторы IF, а встроенные операторы CASE могут стать болезненными, когда многие столбцы становятся условными. Предполагая, что Col1 + Col3 + Col7 имеют тот же тип, а также Col2, Col4 + Col8, вы можете сделать это:

SELECT Col1, Col2 FROM tbl WHERE @Var LIKE 'xyz'
UNION ALL
SELECT Col3, Col4 FROM tbl WHERE @Var LIKE 'zyx'
UNION ALL
SELECT Col7, Col8 FROM tbl WHERE @Var NOT LIKE 'xyz' AND @Var NOT LIKE 'zyx'

Поскольку это единственная команда, есть несколько преимуществ в производительности в отношении кэширования планов. Также оптимизатор запросов быстро устранит те утверждения, в которых @Var не соответствует подходящему значению, не затрагивая механизм хранения.

person Joel Mansford    schedule 14.07.2009