13.2.11.6 Sous-requêtes avec EXISTS ou NOT EXISTS
Si une sous-requête renvoie des lignes du tout, EXISTS
est subquery
TRUE
, et NOT EXISTS
est subquery
FALSE
. 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 x
TRUE
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.