web-dev-qa-db-fra.com

Comment traiter (peut-être) des valeurs nulles dans un PreparedStatement?

La déclaration est

SELECT * FROM tableA WHERE x = ?

et le paramètre est inséré via Java.sql.PreparedStatement 'stmt'

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

Si y est null, l'instruction ne renvoie aucune ligne dans tous les cas car x = null est toujours faux (doit être x IS NULL) .

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

Mais alors je dois définir le même paramètre deux fois. Y a-t-il une meilleure solution?

Merci!

45
Zeemee

Je l'ai toujours fait comme vous l'avez montré dans votre question. Définir le même paramètre deux fois n'est pas une si grande difficulté, n'est-ce pas?

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

Il existe un opérateur ANSI-SQL assez inconnu, IS DISTINCT FROM, qui gère les valeurs NULL. Il peut être utilisé comme ça:

SELECT * FROM tableA WHERE x NOT IS DISTINCT FROM ?

Donc, un seul paramètre doit être défini. Malheureusement, ceci n'est pas supporté par MS SQL Server (2008).

Une autre solution pourrait être, s'il y a une valeur qui est et ne sera jamais utilisée ('XXX'):

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

voudrais simplement utiliser 2 déclarations différentes:

Déclaration 1:

SELECT * FROM tableA WHERE x is NULL

Affirmation 2:

SELECT * FROM tableA WHERE x = ?

Vous pouvez vérifier votre variable et construire l'instruction appropriée en fonction de la condition. Je pense que cela rend le code beaucoup plus clair et facile à comprendre.

EDIT.__ Au fait, pourquoi ne pas utiliser de procédures stockées? Ensuite, vous pouvez gérer toute cette logique NULL dans le SP et simplifier les choses lors de l'appel frontal.

5
dcp

Si vous utilisez par exemple mysql, vous pourriez probablement faire quelque chose comme:

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

Alors tu pourrais faire:

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

Vous devrez vérifier votre plan d'explication pour voir s'il améliore vos performances. Cela signifierait cependant que la chaîne vide est égale à null, elle n'est donc pas accordée et répondrait à vos besoins.

0
Knubo

Dans Oracle 11g, je le fais de cette façon, car x = null est techniquement évalué à UNKNOWN:

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

L'expression avant le OR prend soin d'associer NULL à NULL, puis l'expression après prend en charge toutes les autres possibilités. LNNVL change UNKNOWN en TRUE, TRUE en FALSE et FALSE en TRUE, qui est l'exact opposé de ce que nous voulons, d'où le NOT.

La solution acceptée ne fonctionnait pas pour moi dans Oracle dans certains cas, alors qu’elle faisait partie d’une expression plus large, impliquant une NOT.

0
Brian