129 votes

Clause IN avec NULL ou IS NULL

Postgres est la base de données

Puis-je utiliser une valeur NULL pour une clause IN ? exemple:

SELECT *
FROM tbl_name
WHERE id_field IN ('value1', 'value2', 'value3', NULL)

Je veux limiter aux quatre valeurs.

J'ai essayé la déclaration ci-dessus et cela ne fonctionne pas, eh bien elle s'exécute mais n'ajoute pas les enregistrements avec des champs id NULL.

J'ai également essayé d'ajouter une condition OR mais cela fait juste tourner la requête sans fin en vue.

SELECT *
FROM tbl_name
WHERE other_condition = bar
AND another_condition = foo
AND id_field IN ('value1', 'value2', 'value3')
OR id_field IS NULL

Des suggestions ?

17 votes

Une instruction dans sera analysée de la même manière que champ=val1 ou champ=val2 ou champ=val3. Mettre un nul là-dedans se résumera à champ=null ce qui ne fonctionnera pas.

1 votes

La deuxième requête devrait être correcte. Quelles autres choses sont dans votre clause where ?

0 votes

@Daniel A. White, mis à jour pour refléter la requête avec plus de conditions

182voto

Daniel A. White Points 91889

Une instruction in sera analysée de manière identique à champ=val1 ou champ=val2 ou champ=val3. Mettre un nul là-dedans se réduira à champ=null qui ne fonctionnera pas.

(Commentaire par Marc B)

Je ferais cela pour la clarté

SELECT *
FROM tbl_name
WHERE 
(id_field IN ('valeur1', 'valeur2', 'valeur3') OR id_field IS NULL)

0 votes

Ahh c'est bon, merci! Donc en enveloppant les champs, cela ajoute les deux conditions à la clause WHERE? Juste pour clarification

2 votes

@Phill - c'était un problème d'ordre des opérations.

33voto

Erwin Brandstetter Points 110228

Votre requête échoue en raison de la précédence des opérateurs. AND se lie avant OR!
Vous avez besoin d'une paire de parenthèses, ce n'est pas une question de "clarté", mais une pure nécessité logique.

SELECT *
FROM   tbl_name
WHERE  other_condition = bar
AND    another_condition = foo
AND   (id_field IN ('value1', 'value2', 'value3') OR id_field IS NULL);

Les parenthèses ajoutées empêchent AND de se lier avant OR. S'il n'y avait pas d'autres conditions WHERE (pas de AND), vous n'auriez pas besoin de parenthèses supplémentaires. La réponse acceptée est trompeuse à cet égard.

26voto

Ove Halseth Points 96
SELECT *
FROM tbl_name
WHERE coalesce(id_field,'unik_null_value') 
IN ('value1', 'value2', 'value3', 'unik_null_value')

Ainsi, vous éliminez le null de la vérification. Avec une valeur null dans id_field, la fonction COALESCE retournerait 'unik_null_value' au lieu de null, et en ajoutant 'unik_null_value' à la liste IN, la requête renverrait les posts où id_field est value1-3 ou null.

2 votes

Une petite explication serait utile pour les lecteurs futurs. En quoi votre code aide-t-il à résoudre le problème ?

1 votes

De la documentation: La fonction COALESCE() renvoie la première valeur non nulle dans une liste. Donc, lorsque id_field est null, 'unik_null_value' serait renvoyé et la requête renvoie le bon enregistrement.

16voto

Sushant Butta Points 98

La question telle que répondue par Daniel est parfaite. Je voulais laisser une note concernant les valeurs NULL. Nous devrions faire attention lors de l'utilisation de l'opérateur NOT IN lorsque qu'une colonne contient des valeurs NULL. Vous n'obtiendrez aucun résultat si votre colonne contient des valeurs NULL et que vous utilisez l'opérateur NOT IN. C'est expliqué ici http://www.oraclebin.com/2013/01/beware-of-nulls.html, un très bon article que j'ai découvert et que je voulais partager.

0 votes

Pas sûr combien d'entre nous ont déjà rencontré ce problème, mais j'ai eu exactement ce problème en mélangeant des valeurs nulles et l'opérateur NOT IN et j'ai passé les deux dernières heures à me battre avec. C'EST le coupable...

1 votes

Le lien est mort.

1 votes

La comme est vivante maintenant.

11voto

1000111 Points 11058

Note: Étant donné que quelqu'un prétend que le lien externe est mort dans la réponse de Sushant Butta, j'ai posté le contenu ici comme une réponse séparée.

Méfiez-vous des NULLS.

Aujourd'hui, j'ai rencontré un comportement très étrange de la requête lors de l'utilisation des opérateurs IN et NOT IN. En fait, je voulais comparer deux tables et savoir si une valeur de table b existait dans table a ou non, et connaître son comportement si la colonne contient des valeurs null. J'ai donc créé un environnement pour tester ce comportement.

Nous allons créer la table table_a.

SQL> create table table_a ( a number);
Table créée.

Nous allons créer la table table_b.

SQL> create table table_b ( b number);
Table créée.

Insérez des valeurs dans table_a.

SQL> insert into table_a values (1);
1 ligne créée.

SQL> insert into table_a values (2);
1 ligne créée.

SQL> insert into table_a values (3);
1 ligne créée.

Insérez des valeurs dans table_b.

SQL> insert into table_b values(4);
1 ligne créée.

SQL> insert into table_b values(3);
1 ligne créée.

Nous allons maintenant exécuter une requête pour vérifier l'existence d'une valeur dans table_a en vérifiant sa valeur de table_b en utilisant l'opérateur IN.

SQL> select * from table_a where a in (select * from table_b);
         A
----------
         3

Exécutez la requête ci-dessous pour vérifier la non-existence.

SQL> select * from table_a where a not in (select * from table_b);
         A
----------
         1
         2

La sortie est arrivée comme prévu. Maintenant, nous allons insérer une valeur null dans la table table_b et voir comment les deux requêtes ci-dessus se comportent.

SQL> insert into table_b values(null);
1 ligne créée.

SQL> select * from table_a where a in (select * from table_b);
         A
----------
         3

SQL> select * from table_a where a not in (select * from table_b);

aucune ligne sélectionnée

La première requête s'est comportée comme prévu mais qu'est-il arrivé à la deuxième requête? Pourquoi n'avons-nous obtenu aucune sortie, que se serait-il passé ? Y a-t-il une différence dans la requête? Non.

Le changement concerne les données de la table table_b. Nous avons introduit une valeur null dans la table. Mais comment se fait-il qu'il se comporte ainsi ? Séparons les deux requêtes en utilisant les opérateurs "AND" et "OR".

Première Requête:

La première requête sera traitée en interne quelque chose comme cela. Ainsi, un null ne posera pas de problème ici car mes deux premiers opérandes évalueront soit à true soit à false. Mais mon troisième opérande a = null ne s'évaluera ni à true ni à false. Il s'évaluera seulement à null.

select * from table_a whara a = 3 or a = 4 or a = null;

a = 3  est soit vrai soit faux
a = 4  est soit vrai soit faux
a = null est null

Deuxième Requête:

La deuxième requête sera traitée comme suit. Puisque nous utilisons un opérateur "AND" et que toute valeur autre que true dans l'un des opérandes ne me donnera aucune sortie.

select * from table_a whara a <> 3 and a <> 4 and a <> null;

a <> 3 est soit vrai soit faux
a <> 4 est soit vrai soit faux
a <> null est null

Comment gérons-nous cela ? Nous allons prendre toutes les valeurs not null de la table table_b tout en utilisant l'opérateur NOT IN.

SQL> select * from table_a where a not in (select * from table_b where b is not null);

         A
----------
         1
         2

Alors soyez toujours attentif aux valeurs NULL dans la colonne lors de l'utilisation de l'opérateur NOT IN.

Méfiez-vous des NULL!!

0 votes

Réponse excellente. Je viens de découvrir le problème dans mon travail. Comportement très très étrange d'Oracle.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X