The statement is
SE开发者_开发问答LECT * FROM tableA WHERE x = ?
and the parameter is inserted via 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
).
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. 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).
Another solution could be, if there is a value that is and will be never used ('XXX'):
SELECT * FROM tableA WHERE COALESCE(x, 'XXX') = COALESCE(?, 'XXX')
would just use 2 different statements:
Statement 1:
SELECT * FROM tableA WHERE x is NULL
Statement 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.
If you use for instance mysql you could probably do something like:
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.
In Oracle 11g, I do it this way because x = null
technically evaluates to 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. LNNVL
changes UNKNOWN
to TRUE
, TRUE
to FALSE
and FALSE
to TRUE
, which is the exact opposite of what we want, hence the 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
.
精彩评论