SQL - CASE выражение внутри, где - PullRequest
7 голосов
/ 05 января 2009

Я читал об использовании выражения CASE внутри предложения WHERE:

http://scottelkin.com/sql/using-a-case-statement-in-a-sql-where-clause/

Я пытаюсь использовать это для фильтрации результатов из моего оператора выбора на основе номера контракта, который будет передан приложением пользователя. Мой код в настоящее время выдает ошибку «Неверный параметр» независимо от того, что передано. Я проверил, что SELECT / FROM работают нормально, например, как предложение WHERE без выражения CASE. Вот мой код.

WHERE     (CASE WHEN @ContractNo = 0 THEN @ContractNo ELSE @ContractNo END =
tblContracts.ContractNo)

Избыточность кода предназначена для устранения неполадок, я планирую использовать фильтрацию по шаблону на CASE позже. Я сосредоточен на снижении синтаксиса прямо сейчас. Я считаю, что это должно вернуть все записи, для которых параметр соответствует номеру контракта, хранящегося в таблице. Любая помощь или совет будет принята с благодарностью.

Ответы [ 12 ]

9 голосов
/ 05 января 2009

Вы уверены, что хотите это сделать? Ваша выписка ВСЕГДА возвращает @ContractNo. Я думаю, что вы ищете это:

where 
    case @ContractNo 
        when 0 then tblContracts.ContractNo 
        else @ContractNo 
    end = tblContracts.ContractNo

Фильтр выше говорит: «Дайте мне контракт, где ContractNo равен параметру, или все из них, если параметр равен 0.

Предыдущий фильтр фильтруется только в том случае, если поле номера контракта точно равно параметру.

В любом случае, вы должны сделать это вместо:

where @ContractNo = 0 or @ContractNo = tblContracts.ContractNo

Логика намного проще для понимания, и, кроме того (не цитируйте меня об этом), оптимизатор, вероятно, будет работать лучше вне оператора case.

7 голосов
/ 06 января 2009

После прочтения вашего объяснения есть лучший способ сделать это без CASE:

WHERE @ContractNo = 0 OR tblContracts.ContractNo = @ContractNo

Это вернет только совпадающие номера контракта, если @ContractNo не равно 0, и в этом случае вернут все записи.

Редактировать: Я только что заметил, что casperOne предложил то же самое . Я этого не видел. Создай себя.

2 голосов
/ 05 января 2009

Может быть, вы забыли объявить @ContractNo? Это сопоставимо с 0 и tblContracts.ContractNo?

2 голосов
/ 05 января 2009

Попробуйте опустить скобки, которые в любом случае находятся в неправильном месте - правильные должны быть после "END".

1 голос
/ 06 января 2009

Пост рекурсии решил мою проблему точно.

Я видел жалобы на ясность моего оригинального поста. Что я могу сделать в будущем, чтобы сделать то, что я говорю, более понятным? Я не привык формулировать вопросы о коде и извиняться за любые запутанные вещи, которые у него были. Мне просто нужно было предоставить расширенную информацию, как в моем втором посте?

Еще раз спасибо за помощь.

1 голос
/ 06 января 2009

Причина оператора case, включая целое «Если это 0, задайте параметр, а в противном случае просто укажите параметр», заключалась в том, чтобы протестировать его, чтобы попытаться получить правильный синтаксис. Первоначально я пытался сказать: «Если это 0, то передать«% », чтобы вернуть каждое значение. Код, который я там опубликовал, был потому, что я продолжал получать« Неверный параметр »и полагал, что с моим синтаксисом должно быть что-то не так. Когда Я разделил его на базовое сопоставление параметров следующим образом:

WHERE @ContractNo = tblContracts.ContractNo

он вернул записи в порядке. Позвольте мне объяснить немного больше.

Я извлекаю данные из множества разных таблиц и фильтрую содержимое по информации, не включенной в оператор выбора (т. Е. TblContracts не получает информацию, извлекаемую из него с помощью Select, она используется только в Where). Пользователь будет выбирать из поля со списком, в котором будут разные номера контрактов, а также значение по умолчанию «Все».

У меня будет событие, когда изменится индекс поля со списком. Если это «Все», 0 будет передано в качестве параметра, и я не хочу, чтобы была выполнена фильтрация. В противном случае мне просто нужна информация для этого номера контракта (причина Else @ContractNo).

1 голос
/ 05 января 2009

Переместите закрывающую скобку на перед =, как показано ниже:

WHERE     (CASE WHEN @ContractNo = 0 THEN @ContractNo ELSE @ContractNo END)=tblContracts.ContractNo

Я не вижу, что будет делать этот оператор case, хотя ... вы возвращаете то же самое в случае @ContractNo = 0 или, если это не так ...

Правильный синтаксис:

  Select...
  ...
  Where(
    Case
      When <Condition>
        Then <Return if true>
        Else <Return if false>
      End
 ) = <Whatever is being matched to the output of the case statement>

Независимо от синтаксиса, ваш пример не имеет большого смысла, если вы ищете все элементы, которые соответствуют или имеют номер контракта 0, вы должны сделать:

Select...
...
Where (
  @ContractNo = 0 Or
  @ContractNo = tblContracts.ContractNo
)

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

Редактировать: Должно быть, я немного неправильно прочитал вопрос - отсутствующий параметр обычно означает, что параметр (в данном случае @ContractNo) не объявлен в объеме вашего запроса / процедуры. Но кто-то уже указывал на это, так что я не могу взять на себя ответственность за это.

0 голосов
/ 06 января 2009

когда вы говорите:

Я извлекаю данные из множества разных таблиц и фильтрую содержимое по информации, не включенной в оператор выбора (т. Е. TblContracts не получает информацию, извлекаемую из него с помощью Select, она используется только в Where). Пользователь будет выбирать из поля со списком, в котором будут разные номера контрактов, а также значение по умолчанию «Все».

Тогда мне кажется, что должно быть предложение "Где существует". так как вы не вытаскиваете какую-либо информацию из этой таблицы?!

0 голосов
/ 06 января 2009

Этот синтаксис должен работать (он работает в Oracle)

WHERE CASE WHEN tblContracts.ContractNo = 0 
           THEN @ContractNo 
           ELSE tblContracts.ContractNo
      END = tblContracts.ContractNo
0 голосов
/ 06 января 2009

Номер контракта на самом деле числовой или строка, которая всегда оказывается числовой. Проверьте ваши типы данных между таблицей и параметром и оператором CASE (например, "= 0" или "= '0'")

...