【问题标题】:Building a dynamic no-fail where clause构建动态无失败 where 子句
【发布时间】:2012-06-12 07:33:20
【问题描述】:

我已经建立了一个界面,用户从数据库中获取记录。用户可以选择指定 0 个或多个过滤器。有四个过滤器A、B、C、D(假设这些是某个表中的字段)

我的查询应该是这样的:

select * from table 
where (A = v1 or B = v2 or C = v3) and D = v4

我试图用一种方法来制定查询,而当指定了特定的过滤器时,它会被应用,如果不是,它会被忽略。但这应该适用于所有 16 种情况。

到目前为止,我能想出的是这些方法:

select * from table
where (
    (A = v1 and 1)
    or (B =  v2 and 1)
    or (C = v3 and 1)
    )
    and D = v4

v1 或其他值在未指定时设置为 -1。因此,如果未指定它们,它们将被简单地忽略,因为随后会使用另一个过滤器(来自 A、B、C)。但是在没有指定 A、B 和 C 的情况下,这将失败。在这种情况下,false 与 D 进行 Anded,并且不应用 D。

有没有办法为这种情况提供 where 子句?我也对这个程序的解决方案持开放态度,我通过代码添加或不添加子句,但我更喜欢这种方式。而且我真的不想有很多 if-else 语句。

谢谢!

【问题讨论】:

    标签: mysql sql where-clause boolean-logic relational-algebra


    【解决方案1】:

    如何使用case 构造

      select * 
      from table
      where (A = CASE WHEN v1 IS NOT NULL THEN v1 else '' END)
                OR (B =  CASE WHEN v2 IS NOT NULL THEN v2 else '' END)
                OR (C = CASE WHEN v3 IS NOT NULL THEN v3 else '' END)
                OR (CASE WHEN v1 is null and v2 is null and v3 is null then 1 else 0 end)
      and D = v4
    

    【讨论】:

    • 所以,当 A 和 B 被指定,而 C 不是,C = C 给我真,A 或 B 或真导致 A 和 B 没有被应用,所有的行将是考虑。
    • @Caffeine Yeap。同意。我已经更新了 SQL。我假设 A、B、C 是 varchar 字段。
    • 你可以说A = v1 or B = v2 or ...(我的回答中有更多解释)
    【解决方案2】:

    如果v1-v4 是您要搜索的值,并且所有这些值都是-1,如果未指定,您可以这样做:

    SELECT
      *
    FROM
      table
    WHERE
      (
        (A = v1 OR -1 = v1)
      or 
        (B =  v2 OR -1 = v2)
      or 
        (C = v3 OR -1 = v3)
      )
    AND
      (D = v4 OR -1 = v4)
    

    【讨论】:

    • 假设我指定 A 和 B,但不指定 C。在这种情况下,它将是(A = v1 或 B = v2 或 true)和 D = v4,这将丢弃前两个过滤器。
    【解决方案3】:

    数据库很难优化动态 where 子句。通常,他们会制定一个最适合第一次调用的计划。因此,如果您的第一次搜索是过滤器 A 和 B,则查询计划将为此进行优化。下一个查询也将使用该计划,即使它使用过滤器 C 和 D。在代码中添加 where 子句往往会执行得更好。

    但有可能,例如:

    where  (
               A = @FilterAValue
               or B = @FilterBValue
               or C = @FilterCValue
           )
           and D = coalesce(@FilterDValue, D)
    

    然后您可以使用FilterXValue 参数切换过滤器。如果 A、B 或 C 的过滤器是 null,则仍将评估 or 的其他部分。 A = null or B = 1unknown or B = 1 相同,只有在 B = 1 时才成立。

    【讨论】:

    • 不提供 A、B、C 会怎样?如果我没记错的话,那就是 OP 正在寻找的东西。
    • 那么不会返回任何行(与您的答案相同。)您可以在最后一个or 下方添加or @FilterAValue is null and @FilterBValue is null and @FilterCValue is null 以返回所有行。
    • 最后一种情况检查 v1、v2、v3 是否为空,然后它为所有行返回 true,从而也应用了 D only 过滤器。或者我的问题可能是错误的:-)
    猜你喜欢
    • 1970-01-01
    • 2013-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-02
    • 1970-01-01
    相关资源
    最近更新 更多