SQL Server 2008 - условный запрос - PullRequest
4 голосов
/ 05 мая 2010

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

@isActive int

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

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

Спасибо!

Ответы [ 6 ]

5 голосов
/ 05 мая 2010

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

Условия динамического поиска в T-SQL Эрланда Соммарского

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

Учтите это, OPTION (RECOMPILE) примет этот код (где индекс не может использоваться с этим беспорядком OR s):

WHERE
    (@search1 IS NULL or Column1=@Search1)
    AND (@search2 IS NULL or Column2=@Search2)
    AND (@search3 IS NULL or Column3=@Search3)

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

WHERE
    Column2=@Search2

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

1 голос
/ 05 мая 2010

Вместо того, чтобы использовать -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 не будет оцениваться должным образом. Так что для забавы я изменил свой ответ обратно на то, что запрашивал оригинальный постер, а именно на использование собственного идентификатора для пропуска поиска.

1 голос
/ 05 мая 2010

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

WHERE
   (Customer.IsActive = NULLIF(@isActive, -1) OR NULLIF(@isActive, -1) IS NULL)
1 голос
/ 05 мая 2010
WHERE coalesce(active,1) = (CASE 
                              WHEN @isActive = -1 THEN coalesce(active,1)
                              ELSE @isActive
                            END)
0 голосов
/ 05 мая 2010

Нет элегантного способа - все способы отстой.

ГДЕ @isActive == -1 ИЛИ isActive = @ isActive

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

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

0 голосов
/ 05 мая 2010

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

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