简体   繁体   English

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

[英]How to deal with (maybe) null values in a PreparedStatement?

The statement is 声明是

SELECT * FROM tableA WHERE x = ?

and the parameter is inserted via java.sql.PreparedStatement 'stmt' 并通过java.sql.PreparedStatement'stmt'插入参数

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

If y is null, the statement returns no rows in every case because x = null is always false (should be x IS NULL ). 如果y为null,则语句在每种情况下都不返回任何行,因为x = null始终为false(应为x IS NULL )。 One solution would be 一个解决方案是

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

But then i have to set the same parameter twice. 但后来我必须设置两次相同的参数。 Is there a better solution? 有更好的解决方案吗?

Thanks! 谢谢!

I've always done it the way you show in your question. 我总是以你在问题中展示的方式完成它。 Setting the same parameter twice is not such a huge hardship, is it? 两次设置相同的参数不是那么大的困难,是吗?

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

There is a quite unknown ANSI-SQL operator IS DISTINCT FROM that handles NULL values. 有一个非常未知的ANSI-SQL运算符IS DISTINCT FROM处理NULL值。 It can be used like that: 它可以这样使用:

SELECT * FROM tableA WHERE x NOT IS DISTINCT FROM ?

So only one parameter has to be set. 因此,只需设置一个参数。 Unfortunately, this is not supported by MS SQL Server (2008). 不幸的是,MS SQL Server(2008)不支持这一点。

Another solution could be, if there is a value that is and will be never used ('XXX'): 另一个解决方案可能是,如果有一个值并且将永远不会被使用('XXX'):

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

would just use 2 different statements: 只会使用两种不同的陈述:

Statement 1: 声明1:

SELECT * FROM tableA WHERE x is NULL

Statement 2: 声明2:

SELECT * FROM tableA WHERE x = ?

You can check your variable and build the proper statement depending on the condition. 您可以检查变量并根据条件构建正确的语句。 I think this makes the code much clearer and easier to understand. 我认为这使代码更清晰,更容易理解。

EDIT By the way, why not use stored procedures? 编辑顺便问一下,为什么不使用存储过程? Then you can handle all this NULL logic in the SP and you can simplify things on the front end call. 然后你可以在SP中处理所有这些NULL逻辑,你可以简化前端调用的事情。

In Oracle 11g, I do it this way because x = null technically evaluates to UNKNOWN : 在Oracle 11g中,我这样做是因为x = null技术上评估为UNKNOWN

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

The expression before the OR takes care of equating NULL with NULL, then the expression after takes care of all other possibilities. OR之前的表达式负责将NULL与NULL等同,然后表达式处理所有其他可能性。 LNNVL changes UNKNOWN to TRUE , TRUE to FALSE and FALSE to TRUE , which is the exact opposite of what we want, hence the NOT . LNNVL改变UNKNOWNTRUETRUEFALSEFALSETRUE ,这是我们想要的正好相反,因此NOT

The accepted solution didn't work for me in Oracle in some cases, when it was part of a larger expression, involving a NOT . 在某些情况下,接受的解决方案在Oracle中不起作用,当它是涉及NOT的更大表达式的一部分时。

If you use for instance mysql you could probably do something like: 如果您使用例如mysql,您可能会执行以下操作:

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

Then yo could do: 然后哟可以这样做:

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

You would have to check your explain plan to see if it improves your performance. 您必须检查您的解释计划,看它是否能提高您的表现。 It though would mean that the empty string is equal to null, so it is not granted it would fit your needs. 虽然这意味着空字符串等于null,因此它不会被授予它以满足您的需要。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM