Подтвердить что ты не робот

Как условно фильтровать столбец в предложении WHERE?

ОК, вопрос об условном столбце umpteenth:

Я пишу хранимый proc, который принимает входной параметр, который сопоставляется с одним из нескольких столбцов флага. Каков наилучший способ фильтрации в запрошенном столбце? Я сейчас на SQL2000, но собираюсь перейти на SQL2008, поэтому я возьму современное решение, если доступно.

Таблица, запрошенная в sproc, выглядит как

ID ...  fooFlag  barFlag  bazFlag  quuxFlag
--      -------  -------  -------  --------
01         1        0       0          1
02         0        1       0          0
03         0        0       1          1
04         1        0       0          0

и я хочу сделать что-то вроде

select ID, name, description, ...
from myTable
where (colname like @flag + 'Flag') = 1

поэтому, если я вызову sproc, как exec uspMyProc @flag = 'foo', я вернусь к строкам 1 и 4.

Я знаю, что я не могу выполнить роль в parens непосредственно в SQL. Чтобы сделать динамический SQL, мне придется заполнить весь запрос в строку, объединить параметр @flag в предложении WHERE и затем выполнить строку. Помимо грязного чувства, которое я получаю при выполнении динамического SQL, мой запрос довольно велик (я выбираю пару десятков полей, присоединяюсь к 5 таблицам, вызывая пару функций), поэтому это большая гигантская строка из-за одной строки в 3-строчном WHERE-фильтре.

В качестве альтернативы я мог бы иметь 4 копии запроса и выбирать среди них в операторе CASE. Это оставляет код SQL непосредственно исполняемым (и подвержен синтаксису hilighting и т.д.), Но за счет повторения больших кусков кода, поскольку я не могу использовать CASE только в предложении WHERE.

Есть ли другие варианты? Какие-нибудь сложные комбинации или логические операции, которые могут быть применены? Или я должен просто преодолеть это и выполнить динамический SQL?

4b9b3361

Ответ 1

Есть несколько способов сделать это:

Вы можете сделать это с помощью оператора case.

select ID, name, description, ...
from myTable
where CASE
    WHEN @flag = 'foo' then fooFlag
    WHEN @flag = 'bar' then barFlag
END = 1

Вы можете использовать IF.

IF (@flag = 'foo') BEGIN
    select ID, name, description, ...
    from myTable
    where fooFlag = 1
END ELSE IF (@flag = 'bar') BEGIN
    select ID, name, description, ...
    from myTable
    where barFlag = 1
END

....

У вас может быть сложное предложение where с большим количеством круглых скобок.

select ID, name, description, ...
from myTable
where (@flag = 'foo' and fooFlag = 1)
OR (@flag = 'bar' and barFlag = 1) OR ...

Вы можете сделать это с помощью динамического sql:

DECLARE @SQL nvarchar(4000)

SELECT @SQL = N'select ID, name, description, ...
from myTable
where (colname like ''' + @flag + 'Flag'') = 1'

EXECUTE sp_ExecuteSQL @SQL, N''

Есть больше, но я думаю, что один из них заставит вас идти.

Ответ 2

"В качестве альтернативы я мог бы иметь 4 копии запроса и выбирать среди них в операторе CASE".

Вам не нужно копировать весь запрос 4 раза, просто добавьте все возможности в предложения where в вашей единственной копии запроса:

select ID, name, description, ...
from myTable
where (@flag = 'foo' and fooFlag = 1) OR (@flag = 'bar' and barFlag = 1) OR ...

Ответ 3

Что бы я сделал, это CASE некоторые переменные в начале. Пример:

DECLARE
    @fooFlag int,
    @barFlag int,
    @bazFlag int,
    @quuxFlag int

SET @fooFlag = CASE WHEN @flag = 'foo' THEN 1 ELSE NULL END
SET @barFlag = CASE WHEN @flag = 'bar' THEN 1 ELSE NULL END
SET @bazFlag = CASE WHEN @flag = 'baz' THEN 1 ELSE NULL END
SET @quuxFlag = CASE WHEN @flag = 'quux' THEN 1 ELSE NULL END

SELECT ID, name, description, ...
FROM myTable
WHERE (fooFlag >= ISNULL(@fooFlag, 0) AND fooFlag <= ISNULL(@fooFlag, 1))
AND (barFlag >= ISNULL(@barFlag, 0) AND barFlag <= ISNULL(@barFlag, 1))
AND (bazFlag >= ISNULL(@bazFlag, 0) AND bazFlag <= ISNULL(@bazFlag, 1))
AND (quuxFlag >= ISNULL(@quuxFlag, 0) AND quuxFlag <= ISNULL(@quuxFlag, 1))

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

Ответ 4

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

select id, name, description, ...
from myTable
where (@fooFlag is null or fooFlag = @fooFlag) AND
      (@barFlag is null or barFlag = @barFlag) AND
      ...

Правда, это похоже на идеальный кандидат на создание динамического запроса LINQ и пропущение SPROC после того, как вы перейдете на SQL2008.

Ответ 5

where
   case when @value<>0 then Field else 1 end
   =
   case when @value<>0 then @value else 1 end

Ответ 6

declare @CompanyID as varchar(10) = ''    -- or anyother value

select *  from EmployeeChatTbl chat

  where chat.ConversationDetails like '%'[email protected]+'%' 

                and
                (
                    (0 = CASE WHEN (@CompanyID = '' ) THEN 0 ELSE 1 END) 
                                or 
                    (chat.CompanyID = @CompanyID)
                )

работает

когда присутствует идентификатор компании, тогда фильтрация на его основе выполняется, другой - фильтрация пропускается.