Динамическое включение/выключение логических выражений WHERE на основе параметра

Я использую SQL Server 2012 SELECT внутри хранимой процедуры. SP принимает ряд параметров. Один из этих параметров важен в контексте моего вопроса. Вот псевдокод моего SP:

create proc MyProc
    @mid tinyint,
    @param1 bit = 0
as

    set nocount on

    select
    p.RowId,
    i.Sku,
    i.Condition,
    p.OldPrice,
    p.Delta

    from Prices p 
    join Items i on (p.Sku = i.Sku)

    where
    (p.Mid = @mid)
    and (i.Quantity > 0)
    and (i.IsNew = 0)

    --The condition below must (not)execute depending on param1
    ----------------------------------------------------------------------
    and not (p.Delta = 0 and p.CurrentPrice = p.pMin)
    ----------------------------------------------------------------------

    and p.ThreadId = @thread_id
    order by p.Delta desc

Другими словами, если param1 = 0 запрос выполняет условие WITH, если param1 = 1 то условие игнорируется (как будто его и не было!).

Я пытался играть с булевыми выражениями, но до сих пор не понял.

P.S. Мне не нужен динамический SQL, как в этой статье: Оператор SQL. Я люблю свои предварительно скомпилированные SP.


person Interface Unknown    schedule 20.03.2017    source источник


Ответы (3)


Просто включите проверку в своем предложении where, чтобы если, когда @param1 = 1, вам не было важно условие, которое вы хотите игнорировать.

((@param1 = 1) or not (p.Delta = 0 and p.CurrentPrice = p.pMin))

Возьмем случай @param1 = 0:

==> ((0 = 1) or not (p.Delta = 0 and p.CurrentPrice = p.pMin))
==> (false or not (p.Delta = 0 and p.CurrentPrice = p.pMin))
==> not (p.Delta = 0 and p.CurrentPrice = p.pMin)

Теперь рассмотрим случай @param1 = 1:

==> ((1 = 1) or not (p.Delta = 0 and p.CurrentPrice = p.pMin))
==> (true or not (p.Delta = 0 and p.CurrentPrice = p.pMin))
==> true

Полное измененное заявление:

create proc MyProc
    @mid tinyint,
    @param1 bit = 0
as

    set nocount on

    select
    p.RowId,
    i.Sku,
    i.Condition,
    p.OldPrice,
    p.Delta

    from Prices p 
    join Items i on (p.Sku = i.Sku)

    where
    (p.Mid = @mid)
    and (i.Quantity > 0)
    and (i.IsNew = 0)
    and ((@param1 = 1) or not (p.Delta = 0 and p.CurrentPrice = p.pMin))
    and p.ThreadId = @thread_id
    order by p.Delta desc
person dana    schedule 20.03.2017

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

..... 
where  @param1 = 1 or 
       ( 
          p.Mid = @mid 
          and  i.Quantity > 0 
          and  i.IsNew = 0 
        )
person Ian Kenney    schedule 20.03.2017

Просто включите другое условие в предложение WHERE, и если param1 равно 1, все выражение оценивается как TRUE. Оператор OR — очень удобный способ сделать это.

 AND ( @param1 = 1 OR ( NOT ( p.Delta = 0 AND p.CurrentPrice = p.pMin ) )

Когда @param1 = 1 оценивается как TRUE, тогда не имеет значения, какое выражение, следующее за OR, оценивается как... TRUE, FALSE или NULL/ Это не имеет значения, потому что все три из них: 1) "TRUE OR FALSE", 2) "TRUE OR NULL" и 3) "TRUE OR TRUE" оценивается как TRUE.

Обратите внимание, что это не гарантирует нам, что выражение, следующее за OR, никогда не будет вычисляться. Можно сказать, что результат выражения, следующего за OR, будет проигнорирован, если @param1 = 1 имеет значение TRUE. Но SQL Server может свободно оценивать выражение, следующее за OR. У нас нет контроля над этим.

В некоторых сценариях оценка может вызвать ошибку. Так что в этом смысле выражение не совсем исчезло. В этом конкретном примере я не вижу, какие возможные ошибки может вызвать это выражение, но это в основном потому, что я не вижу типы данных столбцов и не могу знать, какие неявные преобразования типов данных может выполнять SQL Server.


Что касается передачи типа BIT в качестве аргумента, я не знаком с нюансами этого.

Но я бы посоветовал сделать преобразование типа данных явным в SQL.

 AND ( @param1 = CAST(1 AS BIT) OR ( NOT ( p.Delta = 0 AND p.CurrentPrice = p.pMin ) )
person spencer7593    schedule 20.03.2017