web-dev-qa-db-fra.com

Requête MySQL "NOT IN"

Je voulais exécuter une requête simple pour afficher toutes les lignes de Table1 où une valeur de colonne principale n'est pas présente dans une colonne d'une autre table (Table2).

J'ai essayé d'utiliser:

SELECT * FROM Table1 WHERE Table1.principal NOT IN Table2.principal

Cela provoque une erreur de syntaxe. La recherche Google m'a conduit à des forums où les gens disaient que MySQL ne supporte pas NOT IN et que quelque chose d'extrêmement complexe doit être utilisé. Est-ce vrai? Ou est-ce que je commets une terrible erreur?

174

Pour utiliser IN, vous devez avoir un ensemble, utilisez plutôt cette syntaxe:

SELECT * FROM Table1 WHERE Table1.principal NOT IN (SELECT principal FROM table2)
301

L'option de sous-requête a déjà été répondue, mais notez que dans de nombreux cas, un LEFT JOIN peut être un moyen plus rapide de procéder:

SELECT table1.*
FROM table1 LEFT JOIN table2 ON table2.principal=table1.principal
WHERE table2.principal IS NULL

Si vous souhaitez vérifier plusieurs tables pour vous assurer qu'elles ne figurent dans aucune de ces tables (comme dans le commentaire de SRKR), vous pouvez utiliser ceci:

SELECT table1.*
FROM table1
LEFT JOIN table2 ON table2.name=table1.name
LEFT JOIN table3 ON table3.name=table1.name
WHERE table2.name IS NULL AND table3.name IS NULL
163

NOT IN vs NOT EXISTS vs LEFT JOIN/IS NULL dans MySQL

MySQL, comme tous les autres systèmes à l'exception de SQL Server, est capable d'optimiser LEFT JOIN_/_IS NULL pour renvoyer FALSE dès que la valeur correspondante est trouvée, et c'est le seul système qui se souciait de documenter ce comportement. […] Puisque MySQL n'est pas capable d'utiliser les algorithmes de jointure HASH et MERGE, le seul _ANTI JOIN_ dont il est capable est le _NESTED LOOPS ANTI JOIN_

[…]

Essentiellement, [NOT IN] correspond exactement au même plan que _LEFT JOIN_/_IS NULL_, malgré le fait ces plans sont exécutés par les différentes branches de code et ils ont une apparence différente dans les résultats de EXPLAIN. Les algorithmes sont en fait les mêmes et les requêtes se terminent en même temps.

[…]

Il est difficile de dire la raison exacte de [chute de performance lors de l'utilisation de NOT EXISTS] , car cette chute est linéaire et ne semble pas dépendre de distribution des données, nombre de valeurs dans les deux tables, etc., tant que les deux champs sont indexés. Étant donné que MySQL comporte trois éléments de code qui font essentiellement un travail, il est possible que le code responsable de EXISTS effectue une sorte de vérification supplémentaire qui prend du temps supplémentaire.

[…]

MySQL peut optimiser les trois méthodes pour créer une sorte de _NESTED LOOPS ANTI JOIN_. […] Cependant, ces trois méthodes génèrent trois plans différents qui sont exécutés par trois morceaux de code différents. Le code qui exécute le prédicat EXISTS est environ 30% moins efficace […]

C’est la raison pour laquelle le meilleur moyen de rechercher les valeurs manquantes dans MySQL consiste à utiliser un _LEFT JOIN_/_IS NULL_ ou _NOT IN_ plutôt que _NOT EXISTS_.

(emphases ajoutées)

36
engin

Malheureusement, l'utilisation de la clause "NOT IN" dans MySql semble poser problème, la capture d'écran ci-dessous montre l'option de sous-requête renvoyant des résultats erronés:

mysql> show variables like '%version%';
+-------------------------+------------------------------+
| Variable_name           | Value                        |
+-------------------------+------------------------------+
| innodb_version          | 1.1.8                        |
| protocol_version        | 10                           |
| slave_type_conversions  |                              |
| version                 | 5.5.21                       |
| version_comment         | MySQL Community Server (GPL) |
| version_compile_machine | x86_64                       |
| version_compile_os      | Linux                        |
+-------------------------+------------------------------+
7 rows in set (0.07 sec)

mysql> select count(*) from TABLE_A where TABLE_A.Pkey not in (select distinct TABLE_B.Fkey from TABLE_B );
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (0.07 sec)

mysql> select count(*) from TABLE_A left join TABLE_B on TABLE_A.Pkey = TABLE_B.Fkey where TABLE_B.Pkey is null;
+----------+
| count(*) |
+----------+
|      139 |
+----------+
1 row in set (0.06 sec)

mysql> select count(*) from TABLE_A where NOT EXISTS (select * FROM TABLE_B WHERE TABLE_B.Fkey = TABLE_A.Pkey );
+----------+
| count(*) |
+----------+
|      139 |
+----------+
1 row in set (0.06 sec)

mysql> 
7
Legna

Attention NOT IN n'est pas un alias pour <> ANY, mais pour <> ALL!

http://dev.mysql.com/doc/refman/5.0/en/any-in-some-subqueries.html

SELECT c FROM t1 LEFT JOIN t2 USING (c) WHERE t2.c IS NULL

ne peut pas être remplacé par

SELECT c FROM t1 WHERE c NOT IN (SELECT c FROM t2)

Tu dois utiliser

SELECT c FROM t1 WHERE c <> ANY (SELECT c FROM t2)
5
user4554358