Les sous-requêtes
Une sous requete est un SELECT imbriqué dans une autre requete. Les sous requetes sont disponibles à partir de MySQL 4.1
Les sous requetes sont disponibles pour les instructions SELECT INSERT UPDATE DELETE. Il existe différents types de sous requetes.
Les classifications de sous-requêtes
Classification 1
Selon le resultat retourné par la sous-requête, on aura des sous-requêtes de types :
- Scalaire : retourne une seul et unique valeur.
S’utilise partout où on peut mettre une valeur unique (SELECT, WHERE, INSERT, UPDATE) - Colonne : retourne une seul et unique colonne.
Attention : plusieurs lignes. S’utilise dans le WHERE. On ne pourra pas utiliser les opérateurs classiques dans la condition (IN, ALL, SOME, ANY) quand on a plusieurs ligness. - Ligne (row) : retourne une seul et unique ligne.
Attention: plusieurs colonnes. S’utilise dans le WHERE. On pourra l’utiliser avec les opérateurs d’égalité ou de différence uniquement. Autant de lignes que de champs retournés par la sous requete
Pour construire une ligne et la comparer avec la sous requête, on utilisera ROW(val1,val2…) - Table : retourne plusiers colonnes avec plusieurs lignes (colonne + ligne).
S’utilisera dans le FROM. Permetra de créer une table virtuelle
Spécification
Une sous requête est TOUJOURS entre parentheses et sans délimiteur. Pour les sous requêtes de type INSERT/UPDATE/DELETE, la sous requête ne peut se faire sur la table qui est modifiée. On peut inclure dans la sous requête les champs de la requete parente.
Classification 2
La classification 2 porte sur l’indépendance de la sous requête. La sous requête peut-elle s’executer en dehors de la requête parente?
- Non corrélée (indépendante) :
- Corrélée (dépendante) :
Exemples :
Sous requête de type SCALAIRE, NON CORELEE
mysql> SELECT * FROM CountryLanguage WHERE CountryCode = ( SELECT Code FROM Country WHERE Name = 'France' ); +-------------+------------+------------+------------+ | CountryCode | Language | IsOfficial | Percentage | +-------------+------------+------------+------------+ | FRA | Arabic | F | 2.5 | | FRA | French | T | 93.6 | | FRA | Italian | F | 0.4 | | FRA | Portuguese | F | 1.2 | | FRA | Spanish | F | 0.4 | | FRA | Turkish | F | 0.4 | +-------------+------------+------------+------------+ 6 rows in set (0.02 sec)
Sous requête de type COLONNE, CORELEE
mysql> SELECT * FROM CountryLanguage WHERE CountryCode = ( SELECT Code FROM Country WHERE CountryCode = Code ) AND CountryCode = 'FRA'; +-------------+------------+------------+------------+ | CountryCode | Language | IsOfficial | Percentage | +-------------+------------+------------+------------+ | FRA | Arabic | F | 2.5 | | FRA | French | T | 93.6 | | FRA | Italian | F | 0.4 | | FRA | Portuguese | F | 1.2 | | FRA | Spanish | F | 0.4 | | FRA | Turkish | F | 0.4 | +-------------+------------+------------+------------+ 6 rows in set (0.02 sec)
Attention :
mysql> SELECT * FROM Country WHERE Code = (SELECT code FROM Country WHERE continent = 'europe'); ERROR 1242 (21000): Subquery returns more than 1 row mysql> SELECT * FROM Country WHERE Code IN (SELECT code FROM Country WHERE continent = 'europe');
Sous-requête de type ligne
mysql> SELECT * FROM Country WHERE ROW(code,name) IN ( SELECT code, name FROM Co untry WHERE continent = 'europe'); mysql> SELECT ROW(1,2) = ( SELECT 1,2 )
Sous-requête de type table coréllée
mysql> SELECT Capital.Nom FROM ( SELECT City.Id, City.Name AS Nom FROM city INNER JOIN country ON City.Id = Country.Capital) AS Capital WHERE Capital.Id = 1;
Les oppérateurs
Il existe 3 opérateurs pour les sous requêtes :
- ALL : Tout le contenu de la sous-requête
- ANY || SOME :
- EXISTS ( sous-requête ) : retournera true si la sous-requete contient au moins un résultat.
mysql> SELECT Name FROM Country WHERE Population > ALL (SELECT Population FROM Country WHERE Continent = 'Europe'); +---------------+ | Name | +---------------+ | Brazil | | Indonesia | | India | | China | | Pakistan | | United States | +---------------+ 6 rows in set (0.00 sec) SELECT NAME FROM City WHERE id IN (SELECT capital FROm Country); SELECT NAME FROM City WHERE EXISTS (SELECT * FROM Country WHERE City.id=Country.capital);
Convertir une sous-requête en jointure
MySQL est plus performant sur des jointures que sur des sous-requêtes. MySQL recommande donc d’utiliser les jointures. Les jointures sont plus difficiles à lire que les sous requêtes mais sont en général plus rapides.
La conversion est impossible pour les sous-requêtes utilisant des fonctions d’aggrégations dans leur SELECT.
SELECT * FROM t WHERE C IN (SELECT c2 FROM t2 WHERE c3=5); //Donnera SELECT * FROM t INNER JOIN t2 ON t.c = t2.c2 WHERE t2.c3=5; SELECT * FROM t WHERE C NOT IN (SELECT c2 FROM t2); //Donnera SELECT * FROM t LEFT JOIN t2 ON t.c = t2.c2 WHERE c2 IS NULL SELECT * FROM t WHERE C > ANY (SELECT c2 FROM t2); //Donnera SELECT * FROM t INNER JOIN t2 ON t.c > t2.c2;
Les sous-requêtes utilisant IN se convertissent en INNER JOIN tandis que les NOT IN se convertissent en LEFT JOIN
Commentaires récents