Как бороться с (возможно) нулевыми значениями в PreparedStatement? - PullRequest
46 голосов
/ 18 ноября 2010

Заявление

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 ]

37 голосов
/ 18 ноября 2010

Я всегда делал это так, как вы показываете в своем вопросе. Установка одного и того же параметра дважды не такая уж большая проблема, не так ли?

SELECT * FROM tableA WHERE x = ? OR (x IS NULL AND ? IS NULL);
8 голосов
/ 28 марта 2012

Существует совершенно неизвестный оператор ANSI-SQL IS DISTINCT FROM, который обрабатывает значения NULL. Можно использовать так:

SELECT * FROM tableA WHERE x NOT IS DISTINCT FROM ?

Таким образом, должен быть установлен только один параметр. К сожалению, это не поддерживается MS SQL Server (2008).

Другое решение может быть, если есть значение, которое используется и никогда не будет использоваться ('XXX'):

SELECT * FROM tableA WHERE COALESCE(x, 'XXX') = COALESCE(?, 'XXX')
5 голосов
/ 18 ноября 2010

будет просто использовать 2 разных оператора:

Заявление 1:

SELECT * FROM tableA WHERE x is NULL

Заявление 2:

SELECT * FROM tableA WHERE x = ?

Вы можете проверить свою переменную и построить правильный оператор в зависимости от условия. Я думаю, что это делает код намного яснее и легче для понимания.

EDIT Кстати, почему бы не использовать хранимые процедуры? Затем вы можете обрабатывать всю эту NULL-логику в SP и упрощать вызовы внешнего интерфейса.

0 голосов
/ 05 января 2017

В Oracle 11g я делаю это так, потому что x = null технически оценивается как UNKNOWN:

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

Выражение перед OR обеспечивает приравнивание NULL к NULL, затем выражение after заботится обо всех других возможностях. LNNVL изменяется UNKNOWN на TRUE, TRUE на FALSE и FALSE на TRUE, что является полной противоположностью того, что мы хотим, следовательно NOT.

Принятое решение не работало для меня в Oracle в некоторых случаях, когда оно было частью более крупного выражения, включающего NOT.

0 голосов
/ 18 ноября 2010

Если вы используете, например, MySQL, вы, вероятно, могли бы сделать что-то вроде:

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

Тогда вы могли бы сделать:

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

Вы должны проверить план объяснения, чтобы увидеть, еслиэто улучшает вашу производительность.Это, однако, будет означать, что пустая строка равна нулю, поэтому не считается, что она будет соответствовать вашим потребностям.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...