web-dev-qa-db-de.com

Wie gehe ich mit (möglicherweise) Nullwerten in einem PreparedStatement um?

Die Aussage ist

SELECT * FROM tableA WHERE x = ?

und der Parameter wird über Java.sql.PreparedStatement 'stmt' eingefügt

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

Wenn y null ist, gibt die Anweisung in jedem Fall keine Zeilen zurück, da x = null immer false ist (sollte x IS NULL sein). Eine Lösung wäre

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

Aber dann muss ich den gleichen Parameter zweimal einstellen. Gibt es eine bessere Lösung?

Vielen Dank!

45
Zeemee

Ich habe es immer so gemacht, wie Sie es in Ihrer Frage gezeigt haben. Den gleichen Parameter zweimal einzustellen, ist keine große Härte, oder?

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

Es gibt einen ziemlich unbekannten ANSI-SQL-Operator IS DISTINCT FROM, der NULL-Werte verarbeitet. Es kann so verwendet werden:

SELECT * FROM tableA WHERE x NOT IS DISTINCT FROM ?

Es muss also nur ein Parameter eingestellt werden. Leider wird dies von MS SQL Server (2008) nicht unterstützt.

Eine andere Lösung könnte sein, wenn es einen Wert gibt, der niemals verwendet wird ("XXX"):

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

würde nur 2 verschiedene Aussagen verwenden:

Aussage 1:

SELECT * FROM tableA WHERE x is NULL

Aussage 2:

SELECT * FROM tableA WHERE x = ?

Sie können Ihre Variable überprüfen und je nach Bedingung die richtige Anweisung erstellen. Ich denke, das macht den Code viel klarer und verständlicher.

EDIT Warum nicht gespeicherte Prozeduren verwenden? Dann können Sie die gesamte NULL-Logik in SP verarbeiten und die Vorgänge beim Frontend-Aufruf vereinfachen.

5
dcp

Wenn Sie zum Beispiel mysql verwenden, könnten Sie wahrscheinlich Folgendes tun:

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

Dann könnten Sie tun:

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

Sie müssen Ihren Erklärungsplan überprüfen, um zu sehen, ob er Ihre Leistung verbessert. Dies würde jedoch bedeuten, dass die leere Zeichenfolge gleich null ist. Daher wird nicht angenommen, dass sie Ihren Anforderungen entspricht.

0
Knubo

In Oracle 11g mache ich das so, weil x = null technisch zu UNKNOWN ausgewertet wird:

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

Der Ausdruck vor der Variablen OR sorgt dafür, dass NULL mit NULL gleichgesetzt wird, und der Ausdruck after kümmert sich dann um alle anderen Möglichkeiten. LNNVL ändert UNKNOWN in TRUE, TRUE in FALSE und FALSE in TRUE, was genau das Gegenteil von dem ist, was wir wollen, daher die NOT.

Die akzeptierte Lösung funktionierte für mich in Oracle in einigen Fällen nicht, wenn sie Teil eines größeren Ausdrucks war, der eine NOT beinhaltete.

0
Brian