Игнорирование пустого параметра в T-SQL - PullRequest
24 голосов
/ 10 февраля 2009

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

Я делал это так:

(@thing IS NULL or Thing=@thing) 

Это правильно, и если да, то будет ли это плохо работать? Кажется, это намного медленнее, чем создание SQL отдельно.

Какой оптимальный способ сделать это?

ИСПРАВЛЕНО! Смотри ответ Марка Гравелла. Таким образом, использование IS NULL много раз приводит к снижению производительности big .

Ответы [ 10 ]

20 голосов
/ 10 февраля 2009

Как только вы получите больше, чем пару из них, тогда да: он начинает работать довольно медленно. В таких случаях я склонен использовать сгенерированный TSQL - т.е.

DECLARE @sql nvarchar(4000)
SET @sql = /* core query */

IF @name IS NOT NULL
    SET @sql = @sql + ' AND foo.Name = @name'

IF @dob IS NOT NULL
    SET @sql = @sql + ' AND foo.DOB = @dob'

// etc

EXEC sp_ExecuteSQL @sql, N'@name varchar(100), @dob datetime',
        @name, @dob

и т.д.

Обратите внимание, что sp_ExecuteSQL кэширует планы запросов, поэтому любые запросы с одинаковыми аргументами потенциально могут повторно использовать план.

Недостатком является то, что если вы не подпишите SPROC, вызывающей стороне требуются разрешения SELECT для таблицы (а не только разрешения EXEC для SPROC).

12 голосов
/ 10 февраля 2009

Я бы с этим справился.

WHERE Thing = ISNULL(@Thing, Thing)

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

7 голосов
/ 10 февраля 2009

Я обычно использую

WHERE (id = @id OR @id IS NULL)
AND (num = @num OR @num IS NULL)

и т.д.

2 голосов
/ 10 февраля 2009

Метод, который я использовал в прошлом для этого сценария, заключается в использовании функции COALESCE как части моего предложения WHERE. Books Online предоставит более подробную информацию о функции, но вот фрагмент того, как вы можете использовать ее в описанном вами сценарии:

create procedure usp_TEST_COALESCE
(
    @parm1 varchar(32) = null,
    @parm2 varchar(32) = null,
    @parm3 int = null
)
AS

SELECT * 
FROM [TableName]
WHERE Field1 = COALESCE(@parm1, Field1)
AND Field2 = COALESCE(@parm2, Field2)
AND Field3 = COALESCE(@parm3, Field3)

Функция COALESCE вернет первое ненулевое выражение из своих аргументов. В приведенном выше примере, если какой-либо из параметров имеет значение null, функция COALESCE будет использовать значение в базовом поле.

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

1 голос
/ 30 ноября 2010

Посмотрите на следующую ссылку в разделе под названием «Пример: поиск заказов». Здесь подробно рассматриваются все варианты и вы получите превосходный обзор затрат, связанных с каждым из этих вариантов. Предупреждение, будьте очень осторожны при использовании COALESCE, он может не вернуть то, что вы думаете.

С уважением,

Тим

1 голос
/ 10 февраля 2009

Я не уверен, что это «оптимальный» способ, но это именно то, что я делаю в своих хранимых процедурах для тех же целей. Мне кажется, что это быстрее, чем динамически создаваемый запрос, чисто с точки зрения плана выполнения. Другой вариант - создать запрос для каждой комбинации этих «флагов», которые вы передаете, но на самом деле это не так масштабируемо.

0 голосов
/ 16 мая 2019

Если Thing (значение столбца) также может иметь значение Nullable, используйте следующую команду: подход:

WHERE COALESCE(Thing,'')=COALESCE(@thing,Thing,'')
0 голосов
/ 11 января 2010

Спасибо, это было полезно. Я решил использовать метод sp_ExecuteSQL из-за упомянутых потенциальных преимуществ производительности. У меня есть немного другое мнение, которое вы можете найти полезным.

DECLARE @sql nvarchar(4000) 
DECLARE @where nvarchar(1000) =''

SET @sql = 'SELECT * FROM MyTable'

IF @Param1 IS NOT NULL 
    SET @where = @where + ' AND Field1 = @Param1'

IF @Param2 IS NOT NULL 
    SET @where = @where + ' AND Field2 = @Param2' 

IF @Param3 IS NOT NULL 
    SET @where = @where + ' AND Field3 = @Param3' 

-- Add WHERE if where clause exists, 1=1 is included because @where begins with AND
IF @where <> ''
    SET @sql = @sql + ' WHERE 1=1' + @where

--Note that we could also create order parameters and append here
SET @sql = @sql + ' ORDER BY Field1'
0 голосов
/ 10 февраля 2009

когда вы объявляете параметры, если вы устанавливаете для них значение, такое как null, в вашем случае вам не нужно передавать значение в них, если, конечно, вам не нужно Я использую эту возможность для отметки, если необходимо выполнить другой запрос, в особых случаях, когда параметр не равен нулю

Обычно я просто проверяю это так

ЕСЛИ поле НЕДЕЙСТВИТЕЛЬНО

0 голосов
/ 10 февраля 2009

Это метод, который я обычно использую. Я не вижу причин, по которым он будет неэффективным, так как утверждение должно закорачиваться на true, если @thing имеет значение null, и поэтому не требует сканирования таблицы. У вас есть доказательства того, что это сравнение замедляет ваш запрос? Если нет, я бы об этом не беспокоился.

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