代码之家  ›  专栏  ›  技术社区  ›  Zeemee

如何处理PreparedStatement中的(可能)空值?

  •  45
  • Zeemee  · 技术社区  · 15 年前

    声明是

    SELECT * FROM tableA WHERE x = ?
    

    参数通过java.sql.PreparedStatement'stmt'插入

    stmt.setString(1, y); // y may be null
    

    如果 y 为空,语句在任何情况下都不返回行,因为 x = null 总是错误的(应该是 x IS NULL ). 一个解决办法是

    SELECT * FROM tableA WHERE x = ? OR (x IS NULL AND ? IS NULL)
    

    但是我必须设置同一个参数两次。有更好的解决办法吗?

    谢谢!

    5 回复  |  直到 15 年前
        1
  •  37
  •   Paul Tomblin    15 年前

    我一直都是按照你的提问方式来做的。两次设置同一个参数并不是一个很大的困难,不是吗?

    SELECT * FROM tableA WHERE x = ? OR (x IS NULL AND ? IS NULL);
    
        2
  •  8
  •   Zeemee    14 年前

    有一个相当未知的ANSI-SQL运算符 IS DISTINCT FROM 处理空值的。可以这样使用:

    SELECT * FROM tableA WHERE x NOT IS DISTINCT FROM ?
    

    所以只需要设置一个参数。不幸的是,MS-SQL Server(2008)不支持这一点。

    另一种解决方案可能是,如果有一个值是并且永远不会使用('XXX'):

    SELECT * FROM tableA WHERE COALESCE(x, 'XXX') = COALESCE(?, 'XXX')
    
        3
  •  5
  •   dcp    15 年前

    只需要使用两种不同的语句:

    声明1:

    SELECT * FROM tableA WHERE x is NULL
    

    声明2:

    SELECT * FROM tableA WHERE x = ?
    

    您可以检查您的变量并根据条件生成正确的语句。我认为这使得代码更加清晰和容易理解。

    编辑 顺便问一下,为什么不使用存储过程呢?然后,您可以在SP中处理所有这些空逻辑,并且可以简化前端调用的工作。

        4
  •  0
  •   Knubo    15 年前

    如果你使用mysql,你可能会做如下事情:

    select * from mytable where ifnull(mycolumn,'') = ?;
    

    然后你可以:

    stmt.setString(1, foo == null ? "" : foo);
    

    你必须检查你的解释计划,看看它是否能提高你的表现。但这意味着空字符串等于空字符串,因此它不能满足您的需要。

        5
  •  0
  •   Brian    9 年前

    在Oracle 11g中,我这样做是因为 x = null 技术评估为 UNKNOWN :

    WHERE (x IS NULL AND ? IS NULL)
        OR NOT LNNVL(x = ?)
    

    前面的表达式 OR 注意将NULL等同于NULL,然后后面的表达式考虑所有其他可能性。 LNNVL 变化 未知 TRUE , 真的 FALSE 错误的 真的 ,这与我们想要的正好相反,因此 NOT .

    在某些情况下,当它是一个更大表达式的一部分时,接受的解决方案在Oracle中不起作用,涉及 不是 .