2010-05-05 6 views
4

SQL не является одним из моих сильных костюмов. У меня есть база данных SQL Server 2008. Эта база данных хранит процедуру, которая принимает восемь параметров int. Ради сохранения этого вопроса сосредоточенный, я буду использовать один из этих параметров для справки:SQL Server 2008 - Условный запрос

@isActive int 

Каждый из этих параметров INT будет -1, 0 или 1. -1 означает «Неизвестный» или «Дон «Уход». В принципе, мне нужно запросить таблицу таким образом, что если параметр int не равен -1, мне нужно рассмотреть его в моем предложении WHERE. Поскольку существует восемь параметров int, утверждение IF-ELSE не кажется хорошей идеей. В то же время я не знаю, как это сделать?

Есть ли элегантный способ в SQL добавить условие WHERE, если параметр НЕ равен значению?

Спасибо!

ответ

1
WHERE coalesce(active,1) = (CASE 
           WHEN @isActive = -1 THEN coalesce(active,1) 
           ELSE @isActive 
          END) 
+0

да. к сожалению, более 8 случаев - 8! случаях, которые будут запросом монстра. – TomTom

+0

@TomTom, один оператор 'CASE' для каждого параметра. Я не вижу проблемы. –

+0

Использование мозга? это 8 параметров, NOone говорит, что ONLY ONE нежелательно. Один не имеет значения? 8 комбинаций. 2 нерелевантно? 3 нерелевантно? Это намного больше, чем 8 разных случаев. – TomTom

0

.... Where field=case @isActive WHEN -1 THEN field ELSE @isActive END ....

+0

плохой. Сделайте некоторые основные математические данные о том, сколько комбинаций вам нужно - вы будете удивлены. Это будет хранимая процедура монстра без усиления. – TomTom

+0

Что это значит? Это очень хорошо работает с очень большими запросами с большим количеством параметров. – AlexanderMP

+0

Действительно? 8 необязательных параметров - сколько у вас/когда вы получаете? ;) Маленький намек: он не говорит, что только один параметр является необязательным - как насчет всех комбинаций из 2 дополнительных, 3 дополнительных, 4 дополнительных? – TomTom

-5

Существует не элегантный способ - все пути сосать.

WHERE @isActive == -1 ИЛИ IsActive = @isActive

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

Это классический случай, когда хранимые процедуры являются плохими. Запрос должен быть IMHO не с использованием хранимых процедур вообще с самого начала времени, который начался около 15 лет назад, когда кто-то был достаточно умен, чтобы написать первую ORM.

+2

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

+0

Действительно? Как это лучше, чем мнение, которое ВСЕ ПОЛЬЗУЕТЕ ПОЛЬЗОВАТЕЛЮ ОПРЕДЕЛИТЬ ПАРАМЕТРЫ ЗАДАЧИ ДИНАМИЧЕСКИ? Прочтите http://weblogs.asp.net/fbouma/archive/2003/11/18/38178.aspx для базового образования о том, насколько сильно испорчены ваша логика есть. – TomTom

+3

TSQL не использует «==», см. [Операторы сравнения (Transact-SQL)] (http://msdn.microsoft.com/en-us/library/ms188074.aspx), я думаю, вы хотели сказать ' WHERE @isActive = -1 ИЛИ isActive = @ isActive' –

5

лучший источник для динамических условий поиска:

Dynamic Search Conditions in T-SQL by Erland Sommarskog

есть много тонких последствий того, как вы сделаете это, чтобы, если индекс может быть использован или нет. Если вы находитесь на должном выпуске SQL Server 2008, вы можете просто добавить OPTION (RECOMPILE) к запросу, а значение локальной переменной во время выполнения используется для оптимизации.

Рассмотрим это, OPTION (RECOMPILE) будет принимать этот код (где индекс не может быть использован с этой мешанине OR ы):

WHERE 
    (@search1 IS NULL or [email protected]) 
    AND (@search2 IS NULL or [email protected]) 
    AND (@search3 IS NULL or [email protected]) 

и оптимизировать его во время выполнения будет (при условии, что только @ Search2 был принят с использованием значения):

WHERE 
    [email protected] 

и индекс может быть использован (если он есть определенный на Столбец2)

+0

@Villager, вы замените NULL на -1 и будете хорошо идти. –

+0

@ Маркус Адамс, да, вы правы. У меня есть привычка пропускать в NULL условия поиска «игнорировать», поэтому я просто закодировал пример таким образом. Поэтому на основе кода вопроса OPs они похожи на '(@ Search1 = -1 OR Column1 = @ Search1) AND ...' –

+0

KM, кажется, вы единственный умный, кроме моего сообщения среди идиотов, которые не понимают последствий того, что они Пишите здесь. Grats - особенно для опции (recombile), которую я не искал (я никогда не делаю запросов с помощью хранимых процедур для начала). – TomTom

1

узора (column = @param OR @param IS NULL) предоставит вам дополнительные параметры. Вы можете использовать NULLIF, чтобы нейтрализовать ваш -1. Еще лучше было бы разрешить нулевые параметры, вместо использования magic number.

WHERE 
    (Customer.IsActive = NULLIF(@isActive, -1) OR NULLIF(@isActive, -1) IS NULL) 
+0

У вас есть 4 "(", но только 3 ")", если вы измените его на '(Customer.IsActive = NULLIF (@isActive, -1) ИЛИ (NULLIF (@isActive, -1) IS NULL))' it будет работать. –

+0

@KM Совершенно верно. Теперь я удалил дополнительный кронштейн. –

1

Вместо того, чтобы использовать -1 для обозначения того, что вы не знаете или не заботитесь, как насчет использования Null для этого? Довольно многое, для чего это было сделано. Затем вы можете переключиться на бит, а не на Int.

Кроме того, я уверен, что TomTom не согласится, но я думаю, что использование оператора CASE - это способ пойти на этот материал.

Ваш пробег может отличаться, но кажется, что механизм запросов обрабатывает его намного лучше, чем обертывание вещей в IsNull или наличие нескольких операторов OR, которые могут стать довольно запутанными, когда вы начинаете добавлять другие условия.

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

Дополнительная выгода от использования операторов CASE заключается в том, что вы можете добавить немного сложности без особого кода (в отличие от множества предложений OR). Кроме того, первое условие, соответствующее вашим критериям, может предотвратить дополнительные оценки, что не всегда имеет место при работе с OR ...

Итак, для 8 необязательных параметров с -1, поскольку значение используется для игнорирования поиска , что вы в конечном итоге с что-то вдоль линий:

WHERE 
     @Search1 = CASE WHEN @Search1 = -1 THEN @Search1 ELSE @Column1 END 
    AND @Search2 = CASE WHEN @Search2 = -1 THEN @Search1 ELSE @Column2 END 
    AND @Search3 = CASE WHEN @Search3 = -1 THEN @Search1 ELSE @Column3 END 
    AND @Search4 = CASE WHEN @Search4 = -1 THEN @Search1 ELSE @Column4 END 
    AND @Search5 = CASE WHEN @Search5 = -1 THEN @Search1 ELSE @Column5 END 
    AND @Search6 = CASE WHEN @Search6 = -1 THEN @Search1 ELSE @Column6 END 
    AND @Search7 = CASE WHEN @Search7 = -1 THEN @Search1 ELSE @Column7 END 
    AND @Search8 = CASE WHEN @Search8 = -1 THEN @Search1 ELSE @Column8 END 

ПРИМЕЧАНИЕ: Как отметил К., метод NULL дотягивает, если столбцы вы работаете волю потенциально могут иметь значения NULL, так как NULL = NULL не будет правильно оцениваться. Поэтому, для удовольствия, я изменил свой ответ на то, что запросил исходный плакат, который должен использовать свой собственный идентификатор для пропусков поиска.

+0

Gosh, когда-нибудь пробовал это на реальной базе данных? Не слишком ужасно? Зависит от TOTALLY. На каком запросе план хранится. У меня были случаи, когда вещи превращались в 3-минутных монстров со сканами таблицы, благодаря первому запросу, заканчивающемуся просмотром таблицы. – TomTom

+0

И использование OR вместо CASE исправлено? Если у вас нет правильной индексации, и у вас много данных, вы можете столкнуться с проблемами. Я выполнял такие запросы на таблицах с миллионами записей.Конечно, не требуется минут. Но, как я уже сказал, ваш пробег может отличаться. Зависит от дизайна таблицы, того, что запрашивается, сколько данных и каких данных. Есть много способов подойти к проблеме. Просто не понимаю, почему вы так критично относитесь ко всем решениям, кроме своих. –

+1

попробуйте это: 'если null = null print 'wow'', вы заметите, что« ничего себе »никогда не печатает. если вы пройдете в @ search1 как NULL, вы не получите никаких строк, где столбец Column1 будет NULL. В результате это не работает, если ваш столбец может быть нулевым. –

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