13.2.11.6 Sous-requêtes avec EXISTS ou NOT EXISTS
Si une sous-requête renvoie des lignes du tout, EXISTS est subqueryTRUE, et NOT EXISTS est subqueryFALSE. Par exemple :
SELECT column1 FROM t1 WHERE EXISTS (SELECT * FROM t2);
Traditionnellement, une sous-requête EXISTS commence par SELECT *, mais elle pourrait commencer par SELECT 5 ou SELECT column1 ou n’importe quoi d’autre. MySQL ignore la liste SELECT dans une telle sous-requête, cela ne fait donc aucune différence.
Pour l’exemple précédent, si t2 contient n’importe quelles lignes, même des lignes avec rien d’autre que des valeurs NULL, la condition EXISTS est TRUE. Il s’agit en fait d’un exemple peu probable, car une sous-requête EXISTS contient presque toujours des corrélations. Voici quelques exemples plus réalistes :
-
Quel type de magasin est présent dans une ou plusieurs villes ?
SELECT DISTINCT store_type FROM stores WHERE EXISTS (SELECT * FROM cities_stores WHERE cities_stores.store_type = stores.store_type);
Quel type de magasin est présent dans aucune ville ?
SELECT DISTINCT store_type FROM stores WHERE NOT EXISTS (SELECT * FROM cities_stores WHERE cities_stores.store_type = stores.store_type);
Quel type de magasin est présent dans toutes les villes ?
SELECT DISTINCT store_type FROM stores s1 WHERE NOT EXISTS ( SELECT * FROM cities WHERE NOT EXISTS ( SELECT * FROM cities_stores WHERE cities_stores.city = cities.city AND cities_stores.store_type = stores.store_type));
Le dernier exemple est une requête à double imbrication NOT EXISTS. C’est-à-dire qu’elle comporte une clause NOT EXISTS à l’intérieur d’une clause NOT EXISTS. Formellement, elle répond à la question « existe-t-il une ville avec un magasin qui n’est pas dans Stores » ? Mais il est plus facile de dire qu’une NOT EXISTS imbriquée répond à la question « est-ce que xTRUE pour toutes les y ? ».
Dans MySQL 8.0.19 et plus, vous pouvez également utiliser NOT EXISTS ou NOT EXISTS avec TABLE dans la sous-requête, comme ceci :
SELECT column1 FROM t1 WHERE EXISTS (TABLE t2);
Les résultats sont les mêmes que lorsqu’on utilise SELECT * sans WHERE clause dans la sous-requête.