web-dev-qa-db-ja.com

PreparedStatementで(たぶん)null値を処理する方法は?

ステートメントは

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である必要がある)であるため、ステートメントはどの場合でも行を返しません。 1つの解決策は

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

しかし、同じパラメーターを2回設定する必要があります。より良い解決策はありますか?

ありがとう!

47
Zeemee

私はいつもあなたがあなたの質問に示す方法でそれをしました。同じパラメーターを2回設定することはそれほど大きな困難ではありませんか?

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

まったく知られていないANSI-SQL演算子がありますIS DISTINCT FROMはNULL値を処理します。それはそのように使用できます:

SELECT * FROM tableA WHERE x NOT IS DISTINCT FROM ?

したがって、設定する必要があるパラメーターは1つだけです。残念ながら、これはMS SQL Server(2008)ではサポートされていません。

別の解決策は、使用されている値と使用されない値( 'XXX')がある場合です。

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

2つの異なるステートメントを使用するだけです。

ステートメント1:

SELECT * FROM tableA WHERE x is NULL

ステートメント2:

SELECT * FROM tableA WHERE x = ?

変数をチェックして、条件に応じて適切なステートメントを作成できます。これにより、コードがより明確で理解しやすくなると思います。

[〜#〜] edit [〜#〜]ところで、ストアドプロシージャを使用してみませんか?その後、SPでこのすべてのNULLロジックを処理でき、フロントエンドの呼び出しを簡略化できます。

5
dcp

たとえばmysqlを使用する場合、おそらく次のようなことを行うことができます。

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

次に、あなたはそうすることができます:

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

説明計画をチェックして、パフォーマンスが向上するかどうかを確認する必要があります。ただし、空の文字列はnullに等しいため、ニーズに合うとは限りません。

0
Knubo

Oracle 11gでは、x = nullは技術的にUNKNOWNと評価されます:

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

ORの前の式はNULLとNULLの同等化を処理し、その後の式は他のすべての可能性を処理します。 LNNVLUNKNOWNTRUETRUEからFALSEおよびFALSETRUEに変更します。私たちが望むものの正反対なので、NOTです。

Oracleで受け入れられたソリューションは、NOTを含むより大きな式の一部である場合、Oracleでは機能しませんでした。

0
Brian