2009-12-29 5 views
4

Имея проблему с WHERE поиска оператор хотел бы использовать конструкцию как ..SQL Server СЛУЧАЙ, когда и в строительстве

WHERE f.foo IN 
    CASE @bar 
     WHEN 'BAR' THEN 
     ('FOO','BAR',BAZ') 
     WHEN 'BAZ' THEN 
     ('FOOBAR','FOOBAZ') 
    END 

или

WHERE CASE @bar 
     WHEN 'BAR' THEN 
     f.foo IN ('FOO','BAR',BAZ') 
     WHEN 'BAZ' THEN 
     f.foo IN ('FOOBAR','FOOBAZ') 
    END 

где @bar хорошо определен темп переменная соответствующего типа и все, что F определяется хорошо ..

Я получаю ошибку о «ошибка в„“

+0

Это не потерянное, это была моя вторая скорость ввода. –

ответ

5
WHERE (@bar = 'BAR' and f.foo IN ('FOO', 'BAR', 'BAZ')) OR 
     (@bar = 'BAZ' and f.foo IN ('FOOBAR', 'FOOBAZ')) 
+0

Я буду одобрять это ради обслуживания. Если есть другое условие, когда @bar = 'BAR', это гораздо более разборчиво, чем вложенность, которая возникла бы из структуры в вопросе. –

+0

Я также выбрал бы это в следующем ответе, я склоняюсь к скорости, но понимаю, что я не увижу этот код снова в цикле обслуживания. Спасибо всем. –

2

Как дикое предположение, может быть, что вы упускаете а 'в этой строке:

f.foo IN ('FOO','BAR',BAZ') 

должен быть

f.foo IN ('FOO','BAR','BAZ') 
0
WHERE CASE @bar 
     WHEN 'BAR' THEN 
     f.foo IN ('FOO','BAR','BAZ') 
     WHEN 'BAZ' THEN 
     f.foo IN ('FOOBAR','FOOBAZ') 
    END

Вы пропустили' до БАЗА

2

Вы можете удалить случайную часть запроса. Пример:

WHERE ((@bar = 'BAR') AND (f.foo IN ('FOO','BAR','BAZ'))) 
OR ((@bar = 'BAZ') AND (f.foo in ('FOOBAR', 'FOOBAZ'))) 
1

Дело - это выражение, а не утверждение.

3
SELECT * 
FROM … 
WHERE @bar = 'BAR' 
     AND foo IN ('FOO', 'BAR', 'BAZ') 
UNION ALL   
SELECT * 
FROM … 
WHERE @bar = 'BAZ' 
     AND foo IN ('FOOBAR', 'FOOBAZ') 

Это будет наиболее эффективным индекс.

SQL Server будет просто оптимизировать один из запросов, в зависимости от значения @bar, и будет использовать индекс на foo для выполнения оставшегося запроса.

Обновление:

Таблица master имеет 20,000,000 записи с 2,000,000 записей, имеющих name = 't'.

Этот запрос:

DECLARE @s INT 
SET @s = 2 
SELECT * 
FROM master 
WHERE (@s = 1 AND name IN ('t')) OR 
     (@s = 2 AND name IN ('zz')) 

использует и ничего не возвращает в 4 секунд:

|--Parallelism(Gather Streams) 
     |--Index Scan(OBJECT:([test].[dbo].[master].[ix_name_desc]), WHERE:([@s]=(1) AND [test].[dbo].[master].[name]='t' OR [@s]=(2) AND [test].[dbo].[master].[name]='zz')) 

Этот запрос:

DECLARE @s INT 
SET @s = 2 
SELECT * 
FROM master 
WHERE @s = 1 AND name IN ('t') 
UNION ALL 
SELECT * 
FROM master 
WHERE @s = 2 AND name IN ('zz') 

использует CONCATENATION из двух отдельных запросов (один из их оптимизируется) и мгновенно возвращается:

|--Concatenation 
     |--Parallelism(Gather Streams) 
     | |--Filter(WHERE:(STARTUP EXPR([@s]=(1)))) 
     |   |--Index Seek(OBJECT:([test].[dbo].[master].[ix_name_desc]), SEEK:([test].[dbo].[master].[name]='t') ORDERED FORWARD) 
     |--Filter(WHERE:(STARTUP EXPR([@s]=(2)))) 
      |--Index Seek(OBJECT:([test].[dbo].[master].[ix_name_desc]), SEEK:([test].[dbo].[master].[name]='zz') ORDERED FORWARD) 
+0

+1. Я не рассматривал использование UNION в этом случае. Я должен проверить это на использование условия ИЛИ, чтобы увидеть, что является более эффективным. Благодарю. – NotMe

+0

Благодарим вас за создание этого тестового примера. Вы только что убедили меня в том, что я делаю очень-очень неправильно. :) – NotMe

0

Я не верю, что вы можете сделать такую ​​конструкцию, так что вы застряли с чем-то вроде:

where 
    (@bar = 'BAR' and (f.foo = 'FOO' or f.foo = 'BAR' or f.foo = 'BAZ')) or 
    (@bar = 'BAZ' and (f.foo = 'FOOBAR' or f.foo = 'FOOBAZ')) 

или:

where @bar + '_' + f.foo in 
    ('BAR_FOO', 'BAR_BAR', 'BAR_BAZ', 'BAZ_FOOBAR', 'BAZ_FOOBAZ') 
0

оператор СЛУЧАЙ допускает только скаляр вывод. Вы можете обрабатывать его таким образом

WHERE CASE 
      WHEN @bar = 'BAR' AND @foo = 'FOO' THEN 1 
      WHEN @bar = 'BAR' AND @foo = 'BAR' THEN 1 
      WHEN @bar = 'BAR' AND @foo = 'BAZ' THEN 1 
      WHEN @bar = 'BAZ' AND @foo = 'FOOBAR' THEN 1 
      WHEN @bar = 'BAZ' AND @foo = 'FOOBAZ' THEN 1 
      ELSE 0 
     END = 1 
0

Вы можете сделать что-то на этой линии:

WHERE (@bar='BAR' AND f.foo IN ('FOO','BAR','BAZ')) 
    OR (@bar='BAZ' AND f.foo IN ('FOOBAR','FOOBAZ')) 

Это также важно, что вы понимаете, почему ваши фрагменты не работают (кроме несогласованных цитат и других syntaxs ошибки). Оператор CASE не является структурой потока управления. Он не выбирает ветвь кода и вставляет его в ваш SQL. Напротив, он оценивает его содержимое и возвращает выражение, как вызов функции.