Выражение SQL-CASE внутри WHERE

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

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

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

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

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

12 ответов


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

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

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

Edit: Я только что заметил это casperOne предложил то же самое. Я этого не видел. И ты повзрослей.


вы уверены, что хотите сделать это? Ваше заявление case всегда возвращает @ContractNo. Я думаю, что вы ищете это:

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

фильтр выше говорит: "Дайте мне договор, где ContractNo равно параметру или всем, если параметр равен 0.

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

независимо от того, вы должны сделать это:

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

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


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


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


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

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

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


переместите близкую скобку перед = так:

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.

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


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

WHERE @ContractNo = tblContracts.ContractNo

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

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

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


зачем вам вообще нужно заявление по делу?

когда @ContractNo = 0 тогда ( 0 = tblContracts.ContractNo) else @ContractNo тогда (@ContractNo = tblContracts.ContractNo)

Это не имеет смысла, так как вы можете просто написать это как

где @contractNo = tblContracts.contractNo


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


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

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

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

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

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