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

问题描述 投票:0回答:5

声明是

SELECT * FROM tableA WHERE x = ?

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

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

如果

y
为 null,则该语句在每种情况下都不会返回任何行,因为
x = null
始终为 false(应为
x IS NULL
)。 一种解决方案是

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

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

谢谢!

java null prepared-statement
5个回答
42
投票

我一直按照您在问题中显示的方式这样做。 设置相同的参数两次并不是那么困难,不是吗?

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

10
投票

有一个相当未知的 ANSI-SQL 运算符

IS DISTINCT FROM
可以处理 NULL 值。可以这样使用:

SELECT * FROM tableA WHERE x IS NOT DISTINCT FROM ?

因此只需设置一个参数。不幸的是,MS SQL Server (2008) 不支持此功能。

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

SELECT * FROM tableA WHERE COALESCE(x, 'XXX') = COALESCE(?, 'XXX')

6
投票

只会使用两种不同的语句:

声明1:

SELECT * FROM tableA WHERE x is NULL

声明2:

SELECT * FROM tableA WHERE x = ?

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

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


1
投票

如果您使用例如 mysql,您可能可以执行以下操作:

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

那么你可以这样做:

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

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


0
投票

在 Oracle 11g 中,我这样做是因为

x = null
在技术上评估为
UNKNOWN
:

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

OR
之前的表达式负责将 NULL 与 NULL 等同,然后之后的表达式负责所有其他可能性。
LNNVL
UNKNOWN
更改为
TRUE
,将
TRUE
更改为
FALSE
,将
FALSE
更改为
TRUE
,这与我们想要的完全相反,因此是
NOT

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

NOT

© www.soinside.com 2019 - 2024. All rights reserved.