112 votes

Sélectionner NOT IN dans plusieurs colonnes

J'ai besoin d'implémenter la requête suivante :

SELECT * 
FROM   friend 
WHERE  ( friend.id1, friend.id2 ) 
         NOT IN (SELECT id1, 
                        id2 
                 FROM   likes) 

Mais NOT IN ne peut pas être mis en œuvre sur plusieurs colonnes. Comment dois-je écrire cette requête ?

0 votes

3 votes

Votre code est valide Standard Full SQl-92 syntaxe. Vous avez seulement ajouté la balise "sql" à votre question. Si vous vouliez parler d'un produit particulier (par exemple SQL Server), vous devriez trouver une balise spécifique pour celui-ci (la syntaxe n'est pas prise en charge par SQL Server, d'ailleurs).

0 votes

S'agirait-il d'OpenEdge ? Malheureusement, Open Edge n'implémente pas la spécification SQL-92 complète et ni l'un ni l'autre not in o not exists travail, seul un left join where = null fonctionnera avec OpenEdge.

142voto

Michał Powaga Points 8949

Je ne suis pas sûr que vous y pensiez :

select * from friend f
where not exists (
    select 1 from likes l where f.id1 = l.id and f.id2 = l.id2
)

cela ne fonctionne que si id1 est lié à id1 et id2 à id2, pas les deux.

0 votes

Ça a marché dans mon cas. Je voulais juste exclure les lignes dont les colonnes A et B existaient dans une table d'exclusion. SQL Server 2016.

0 votes

Il fonctionne avec MySQL. Je l'ai utilisé à la place de EXCEPT, car MySQL ne supporte pas la syntaxe EXCEPT.

6 votes

Cela ne fonctionnera pas dans SQL Server si id1 ou id2 comprennent des valeurs NULL, vous devrez utiliser la fonction coalesce : select 1 from likes l where coalesce(f.id1, 0) = coalesce(l.id1, 0) and coalesce(f.id2, 0) = coalesce(l.id2, 0)

24voto

Erwin Brandstetter Points 110228

Un autre SGBD mystérieusement inconnu. Votre syntaxe est parfaitement adaptée à PostgreSQL. D'autres styles de requêtes peuvent être plus rapides (en particulier l'option NOT EXISTS ou une variante LEFT JOIN ), mais votre demande est parfaitement légitime.

Soyez conscient des pièges à éviter avec NOT IN Cependant, lorsqu'il s'agit de NULL valeurs :

Variante avec LEFT JOIN :

SELECT *
FROM   friend f
LEFT   JOIN likes l USING (id1, id2)
WHERE  l.id1 IS NULL;

Voir la réponse de @Micha pour le NOT EXISTS variante.
Une évaluation plus détaillée de quatre variantes de base :

10voto

vacolane Points 81

J'utilise une méthode qui peut sembler stupide mais qui fonctionne pour moi. Je concatène simplement les colonnes que je veux comparer et j'utilise NOT IN :

SELECT *
FROM table1 t1
WHERE CONCAT(t1.first_name,t1.last_name) NOT IN (SELECT CONCAT(t2.first_name,t2.last_name) FROM table2 t2)

4 votes

Concat va donner de fausses correspondances. (par exemple, "ab", "cd" et "a", "bcd").

0 votes

Donc peut-être ajouter un séparateur au milieu, comme "ab" + "/" + "cd".

4 votes

Vous pouvez éviter les fausses correspondances en utilisant un séparateur dont il est garanti qu'il ne sera pas utilisé par l'une ou l'autre des colonnes, mais le problème majeur est que votre requête nécessite un balayage complet de la table en raison de l'utilisation de WHERE CONCAT. Les index sur les colonnes first_name ou last_name ne seront pas utiles au planificateur de requêtes.

-5voto

Raoul George Points 1613

Vous devriez probablement utiliser NOT EXISTS pour plusieurs colonnes.

2 votes

Comment ? Votre réponse ne fournit aucun détail.

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