Formation PUB200 : MySQL, 2018 Requêtes imbriquées ou sous-requêtes

11.1 Condition qui dépend d'une autre requête


Dans certaines requêtes, la condition WHERE est déterminée par le résultat d'une autre requête. La condition sera donc déterminée par une requête imbriquée, aussi appelé sous-requête.

Il s'agit de faire un SELECT dans un SELECT.

Ex : pour trouver le nom du ou des derniers mécaniciens embauchés :

MySQL

SELECT prenom, nomfamille

FROM mecaniciens

WHERE embauche =

(

   SELECT MAX(embauche)

   FROM mecaniciens

);

Voici l'explication : lorsque le SGBD exécute la requête, il doit trouver la date maximale d’embauche puis il doit trouver les mécaniciens qui ont été embauchés à cette date. Il fait donc au total deux requêtes, d’où le besoin d’effectuer une sous-requête.

Notez que lorsque la première requête spécifie qu'un champ doit être comparé à la sous-requête (=, <, >, ...), la sous-requête devra ne retourner qu'un seul enregistrement.

Lors de l'exécution de la requête, la sous-requête sera toujours exécutée en premier.

MySQL supporte les requêtes imbriquées depuis la version 4.1

Contre-exemples

Les quelques contre-exemples suivants vous aideront à déceler le problème pour les erreurs les plus fréquemment commises.

Si on oublie les parenthèses

Si vous entrez la requête suivante (notez l'absence de parenthèses de la sous-requête) :

MySQL

SELECT prenom, nomfamille

FROM mecaniciens

WHERE embauche =

SELECT MAX(embauche)

FROM mecaniciens;

phpMyAdmin vous donnera le message : erreur #1064 - Erreur de syntaxe près de 'SELECT MAX(embauche) FROM mecaniciens' à la ligne 4.

Manque parenthèses sous-requête

Il est donc impossible d'effectuer une sous-requête sans l'entourer de parenthèses.

Si on tente l'expérience sans sous-requête

Les novices peuvent être tentés de monter la requête suivante :

MySQL

SELECT prenom, nomfamille

FROM mecaniciens

WHERE embauche = MAX(embauche);

phpMyAdmin vous donnera le message : erreur #1111 - Utilisation invalide de la clause GROUP.

Tentative sans sous-requête

Autre tentative sans sous-requête

Voici une autre tentative pour obtenir le résultat sans effectuer de sous-requête :

MySQL

SELECT prenom, nomfamille, MAX(embauche)

FROM mecaniciens;

Cette requête semble fonctionner. Cependant, on n’obtient pas le bon nom. Pourquoi? Le SGBD tente de lister les noms donc commence par sortir le premier nom de la liste. Comme une des informations demandées utilise une fonction d’agrégation, il sort le résultat de la fonction et, comme une fonction d’agrégation ne retourne qu’un enregistrement, il arrête le travail. On voit donc qu’il doit vraiment exécuter 2 requête pour réussir son travail.

Rappelez-vous de toujours vérifier les résultats d'une requête en consultant les données brutes de la BD avant de conclure que la requête est correcte.

Encore un test sans sous-requête

Tentons un dernier essai :

MySQL

SELECT prenom, nomfamille 

FROM mecaniciens 

ORDER BY embauche DESC 

LIMIT 1;

Ici encore, la requête semble fonctionner. Cependant, cette requête ne retourne qu'un enregistrement alors qu'il y a deux personnes embauchées à la date la plus récente.  Si on ne vérifie pas les informations dans la BD, on risque de ne jamais se rendre compte de l'erreur...

Si la sous-requête retourne plus d'un enregistrement

Il a été précisé que lorsque la sous-requête est utilisée dans une égalité, elle ne doit retourner qu'un seul enregistrement. Voici ce qui arrivera si ce n'est pas le cas.

MySQL

SELECT prenom, nomfamille

FROM mecaniciens

WHERE embauche =

(

   SELECT embauche

   FROM mecaniciens

);

phpMyAdmin retournera l'erreur suivante : #1242 - Subquery returns more than 1 row.

Sous-requête retourne plus d'un résultat

Si cela vous arrive, vous comprendrez que la sous-requête retourne plus d'un enregistrement donc elle doit être corrigée, possiblement à l'aide d'une fonction d'agrégation.

▼Publicité

Veuillez noter que le contenu de cette fiche vous est partagé à titre gracieux, au meilleur de mes connaissances et sans aucune garantie.
Merci de partager !
Soumettre