Le langage SQL permet d'imbriquer les requêtes les unes dans les autres à la manière de poupées russes. Cette technique consiste à écrire une requête interne directement dans la clause WHERE ou HAVING d'une autre requête dite externe. Le résultat d'une requête interne fournit des valeurs à la condition de recherche utilisée par la requête externe. Une requête interne est communément appelée sous-requête. Les sous-requêtes peuvent s'imbriquer jusqu'à plusieurs niveaux de profondeur. Elles illustrent parfaitement l'orientation ensembliste de SQL comme nous le verrons au travers des exemples de ce paragraphe.
Pour illustrer le concept de sous-requête, considérons la requête SQL permettant de récupérer le nom et l'adresse du client qui a passé la commande 1008. Cette requête peut utilisé la technique de la jointure présenté dans le paragraphe précédent:
Requête récupérant le nom et l'adresse du client qui a passé la commande 1008 à l'aide d'une jointure
En terme ensembliste, l'instruction SQL ci-dessus consiste à déterminer d'abord un sous-ensemble de la table Commande répondant au critère CommandeID=1008, puis à mettre en correspondance les lignes de ce sous-ensemble avec celles de la table Client qui ont la même valeur ClientID. Dans notre exemple, le sous-ensemble tiré de Commande contient une seule ligne qui correspond à un seul client (une seule ligne) dans la table Client.
Cette requête peut être écrite de manière équivalente en utilisant la technique des sous-requêtes:
Requête récupérant le nom et l'adresse du client qui a passé la commande 1008 à l'aide d'une sous-requête
Remarquons que la sous-requête, écrite ci-dessus entre parenthèse, suit la syntaxe bien connues des instructions SQL et constitue à elle seule une requête indépendante. Par conséquent, le résultat de ladite sous-requête sera une ensemble de lignes. Dans notre exemple, nous savons que cet ensemble contient une valeur unique, car il existe un seul ClientID ayant passé la commande 1008. Cette valeur unique sera utilisée comme valeur de comparaison dans la clause WHERE de la requête externe.
La technique des sous-requêtes est applicable dans cet exemple car la valeur de CommandeID n'apparaît pas dans le résultat final mais uniquement comme critère de sélection dans la requête interne. Si la requête consistait à récupérer le nom, l'adresse et le numéro de commande du client qui a passé la commande 1008, la technique des sous-requêtes n'aurait pas pu être appliquée. En effet, les données d'une sous-requête ne peuvent pas être incluses dans le résultat final.
Une sous-requête produit un résultat qui doit être comparé à UN attribut tel que ClientID. Par conséquent, la clause SELECT de la sous-requête doit spécifier UN seul attribut comme le montre l'exemple suivant:
Comme l'exige la syntaxe, la liste de sélection dans la sous-requête ci-dessus contient un seul attribut, à savoir ClientID, dont les valeurs seront utilisées dans la clause WHERE de la requête externe. Nous utilisons l'option DISTINCT dans la clause SELECT car nous ne nous intéressons pas au nombre de commandes passées par un client quelconque mais uniquement aux clients ayant passé au moins une commande. Pour chaque client dans Commande, la sous-requête doit extraire son ClientID une seule fois quel que soit le nombre de commandes qu'il a passées.
L'exemple suivant illustre l'emploi du qualificateur NOT et démontre qu'il est possible d'écrire une jointure dans une requête interne:
Requête récupérant la liste des noms des clients qui n'ont pas commandé l'ouvrage "Rupture de contrat"
La requête interne retourne la liste des numéros de clients qui ont commandé l'ouvrage "Rupture de contrat". La requête externe affiche la liste des noms de clients dont l'identifiant ClientID ne figurent pas (NOT IN) dans la liste fournie par la requête interne.
Rédigez les requêtes SQL suivantes permettant d'obtenir des informations à partir de la base de données Librairie. Vos solutions contiendront des sous-requêtes et devront engendrer les mêmes tables que celles proposées dans le lien "Résultat" situé à la suite de l'énoncé de chaque requête: