根据参数动态切换 on/off WHERE 布尔表达式

Dynamically switching on/off WHERE boolean expression(s) based on a parameter

我在存储过程中使用 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:Building dynamic where condition in SQL statement。我喜欢我的预编译 SP。

只需在您的 where 子句中包含一个检查,这样 if when @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

你可以使用or条件来实现,如果or中的第一个语句的计算结果为真,则不会尝试第二个

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

只需在 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 之后的表达式。我们可以说,当 @param1 = 1 为 TRUE 时,OR 后面的表达式的 result 将被忽略。但是 SQL 服务器可以自由计算 OR 之后的表达式。我们无法控制这一点。

在某些情况下,评估可能会引发错误。所以从这个意义上说,表达并没有完全消失。在这个特定的例子中,我没有看到表达式可能会抛出什么错误,但这主要是因为我没有看到列的数据类型,而且我不知道什么隐式数据类型转换 SQL 服务器可能正在表演。


至于将 BIT 类型作为参数传递,我不熟悉其中的细微差别。

但我建议我们在 SQL

中明确进行数据类型转换
 AND ( @param1 = CAST(1 AS BIT) OR ( NOT ( p.Delta = 0 AND p.CurrentPrice = p.pMin ) )