Comment gérer (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.setSsortingng(1, y); // y may be null 

Si y est nul, l’instruction ne retourne aucune ligne dans tous les cas, car x = null est toujours faux (doit être x IS NULL ). Une solution serait

 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!

Je l’ai toujours fait comme vous le montrez dans votre question. Définir deux fois le même paramètre n’est pas une difficulté énorme, non?

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

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, cela n’est pas pris en charge 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') 

utiliserait simplement 2 déclarations différentes:

État 1:

 SELECT * FROM tableA WHERE x is NULL 

Déclaration 2:

 SELECT * FROM tableA WHERE x = ? 

Vous pouvez vérifier votre variable et créer la déclaration appropriée en fonction de la condition. Je pense que cela rend le code beaucoup plus clair et plus facile à comprendre.

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

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

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

Alors tu pourrais faire:

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

Vous devrez vérifier votre plan d’explication pour voir si cela améliore vos performances. Cela signifierait cependant que la chaîne vide est égale à null, donc elle ne lui est pas accordée.

Dans Oracle 11g, je le fais de cette manière car x = null techniquement évalué à UNKNOWN :

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

L’expression avant le OR prend en compte NULL avec NULL, alors l’expression après prend en compte toutes les autres possibilités. LNNVL change UNKNOWN à TRUE , TRUE à FALSE et FALSE à TRUE , ce qui est l’exact opposé de ce que nous voulons, donc le NOT .

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