Médaille
N°1 pour apprendre & réviser du collège au lycée.

Tri de données avec le langage SQL

Déjà plus de

1 million

d'inscrits !

Introduction :

Nous savons ce qu'est une base de données relationnelle, nous savons aussi la mettre en œuvre et l'utiliser grâce au SGBD et au langage SQL. Nous achevons ce chapitre sur les bases de données avec un cours destiné à compléter nos connaissances sur les requêtes SQL.
Il s'agira ici d'apprendre à formuler des recherches plus élaborées, faisant appel à des fonctions de tri ou de calcul. Nous verrons également comment articuler une requête SQL touchant plusieurs tables à la fois. Commençons donc par nous pencher sur les fonctions de calcul et transformation auxquelles il est possible d'avoir recours dans une commande SQL.

Calculs et transformations dans une requête

À l'occasion d'une requête, il est possible de demander le résultat d'un calcul opéré sur la valeur d'une ou plusieurs colonnes pour chaque ligne concernée. On peut aussi demander le résultat d'un calcul qui porte sur l'ensemble des lignes d'une table. D'autres manipulations sont également possibles.

Calcul portant sur la valeur d'une colonne

Le résultat d'un calcul effectué sur la valeur d'une colonne est stocké dans une colonne qui vient s'ajouter à la table résultat de la requête.
Ainsi, on peut effectuer des calculs impliquant une ou plusieurs colonnes en ayant recours aux opérateurs arithmétiques suivants :

++ addition
- soustraction
* multiplication
// division
%\% reste dans la division
bannière exemple

Exemple

Nous voulons la liste des recettes du club, avec leur nom et leur durée en seconde. Il est donc nécessaire d'effectuer un calcul avec la colonne duree qui est exprimée et stockée en minutes dans la base de données. Voici la commande SQL qui en résulte :

SELECT nomrecette, (duree * 60) AS dureeSecondes
FROM recette;

bannière à retenir

À retenir

La clause AS permet de baptiser le nom de la nouvelle colonne destinée à recueillir le résultat du calcul.

Voici la table recette :

idRecette nomRecette niveau duree categorie idAdherent
1 Mayonnaise difficile 15 sauce 7
2 Omelette facile 5 plat 6
3 Pâte brisée moyen 20 autre 6
4 Quatre-quarts facile 10 dessert 4
5 Purée de carottes moyen 15 accompagnement 2
6 Poulet rôti facile 15 plat 2
7 Sole meunière difficile 20 plat 7

Le résultat obtenu est une table de deux colonnes :

nomRecette dureeSecondes
Mayonnaise 900
Omelette 300
Pâte brisée 1200
Quatre-quarts 600
Purée de carottes 900
Poulet rôti 900
Sole meunière 1200

Calcul portant sur l'ensemble des lignes d'une table

Entre autres calculs et transformations, penchons-nous sur les fonctions statistiques simples que l'on peut appeler avec SQL, recensées dans le tableau qui suit :

COUNT(*) Nombre de lignes dans la table
MAX(colonnex) valeur maximum dans la colonne
MIN(colonnex) valeur minimum dans la colonne
AVG(colonnex) valeur moyenne de la colonne
SUM(colonnex) somme des valeurs de la colonne
bannière exemple

Exemple

Si l'on veut connaître la durée moyenne des recettes du club de cuisine, en minutes, on passera la commande SQL suivante au SGBD :

SELECT AVG(duree) AS dureeMoyenne
FROM recette;

Le résultat alors retourné est une table d'une colonne et d'une ligne :

dureeMoyenne
14.2857

Et si l'on souhaite connaître le nombre d'adhérent·e·s du club de cuisine, il suffira d’entrer la commande suivante :

SELECT COUNT(*) AS nbAdherents
FROM adherent;

Voici la table adherent :

idAdherent nomAdherent prenom mail numero rue idVille passe telephone
1 DURAND Jacques j.durand@orange.fr 16b rue brune 1 motdepass1 0601020304
2 DUVAL Paul paul.d@sfr.fr 135 avenue rouge 4 motdepass2 0704030201
3 DELORS Sophie sodelors@outlook.com 22a bd vert 3 motdepass3 0606060202
4 VERGER Jehan jverger@aol.com 4ter impasse jaune 5 motdepass4 0601020102
5 MONVILLE Fleur fleur1212@free.fr 9 sente aux loups 2 motdepass5 0707020201
6 BRIARD Paul paul.briard27@hotmail.fr 191 rue violette 4 motdepass6 0612345678
7 LÉGER Marguerite mag0506@perso.com 17 place noire 3 motdepass7 0687654321
8 FLAMAND Lise flise@gmail.com 329 route bleue 2 motdepass8 0632323232

Et voici le résultat retourné, qui est une table d'une colonne et d'une ligne :

nbAdherents
8
bannière astuce

Astuce

On remarquera au passage qu'on ne spécifie pas une colonne en particulier dans la fonction COUNT puisqu'il s'agit de compter le nombre de toutes les lignes dans la table, sans s'intéresser à une colonne en particulier.

Autres manipulations sur les données

D'autres transformations sur les colonnes sont possibles lors d'une requête d'interrogation, comme par exemple le passage en majuscule d'une colonne de type chaîne de caractères avec la fonction UPPER. On peut également demander l'extraction du mois d'une date grâce à la fonction MONTH.

bannière exemple

Exemple

Voici la requête permettant d'obtenir la liste des numéros, noms et prénoms des adhérent·e·s affichés en majuscules de notre club de cuisine :

SELECT idAdherent, UPPER(nomAdherent) AS nomMaj, UPPER(prenom) AS prenomMaj
FROM adherent;

Le résultat est une table de trois colonnes :

idAdherent nomMaj prenomMaj
1 DURAND JACQUES
2 DUVAL PAUL
3 DELORS SOPHIE
4 VERGER JEHAN
5 MONVILLE FLEUR
6 BRIARD PAUL
7 LEGER MARGUERITE
8 FLAMAND LISE

Il peut être parfois intéressant d'effectuer des calculs statistiques portant sur des groupes de lignes et toutes les lignes d'une table. On aura alors recours à des opérations d'agrégation. Nous allons voir également que l'on peut exiger d'une requête qu'elle nous restitue sa table résultat de manière triée.

Agrégats et tri

Calcul sur agrégats

On effectue une opération dite d'agrégation pour regrouper les lignes d'une table par la même valeur qu'elles contiennent dans une colonne. L'objectif d'effectuer une agrégation est, en général, de pratiquer des calculs statistiques sur les groupes ainsi constitués.

bannière à retenir

À retenir

La clause employée pour pratiquer une agrégation est GROUP BY :

SELECT nomColonne1, fonction statistique
FROM nomTable
GROUP BY nomColonne1;

bannière exemple

Exemple

Notre club de cuisine souhaite connaître le nombre de recettes dans sa base pour chaque catégorie.
La table des recettes est la suivante :

idRecette nomRecette niveau duree categorie idAdherent
1 Mayonnaise difficile 15 sauce 7
2 Omelette facile 5 plat 6
3 Pâte brisée moyen 20 autre 6
4 Quatre-quarts facile 10 dessert 4
5 Purée de carottes moyen 15 accompagnement 2
6 Poulet rôti facile 15 plat 2
7 Sole meunière difficile 20 plat 7

Il suffira donc de transmettre la requête SQL suivante au SGBD :

SELECT categorie, COUNT(*) AS nombre
FROM recette
GROUP BY categorie;

La table résultat qui nous sera alors retournée sera par conséquent :

categorie nombre
sauce 1
plat 3
autre 1
dessert 1
accompagnement 1

Restriction sur le résultat d'un calcul sur agrégat

On peut ajouter une opération de filtrage à la table résultant d'une opération sur agrégat. La clause HAVING permet d'exprimer le critère de filtrage sur cette table résultat.

bannière exemple

Exemple

Le club décide de recueillir les seules catégories de recette dont la durée moyenne est au moins de 14 minutes.

La commande SQL suivante nous permet de calculer la durée moyenne des recettes par catégorie :

SELECT categorie, AVG(duree) AS dureeMoyenne
FROM recette
GROUP BY categorie;

La table résultat qui est restituée est ainsi :

categorie dureeMoyenne
sauce 15.0000
plat 13.3333
autre 20.0000
dessert 10.0000
accompagnement 15.0000

En complétant la commande par la clause HAVING dureeMoyenne >= 14, on ne retient que les catégories figurant dans la table résultat dont la colonne dureeMoyenne répond au critère du filtre :

SELECT categorie, AVG(duree) AS dureeMoyenne
FROM recette
GROUP BY categorie
HAVING dureeMoyenne >= 14;

Le résultat qui est restitué ne nous étonne pas :

categorie dureeMoyenne
sauce 15.0000
autre 20.0000
accompagnement 15.0000

Tris

Lorsque l'on effectue une requête, par défaut, la table résultat qui est restituée n'est pas triée.

bannière à retenir

À retenir

Pour que ce soit le cas, on emploie le mot-clé ORDER BY suivi de la ou les colonnes sur lesquelles doit porter le tri.

bannière astuce

Astuce

Si plusieurs colonnes sont spécifiées dans la consigne de tri, alors le tri s'effectuera d'abord sur les valeurs de la colonne la plus à gauche, puis selon les valeurs des colonnes données pour le tri de gauche à droite.

Notons par ailleurs que le tri s'effectue par défaut de manière ascendante. L'option DESC inversera le tri pour le critère concerné.

bannière exemple

Exemple

Notre club de cuisine souhaite avoir la liste de ses adhérent·e·s constituée de leurs numéros, noms et prénoms mis en majuscules, triée par nom, puis par prénom.
Reprenons la table des adhérent·e·s :

idAdherent nomAdherent prenom mail numero rue idVille passe telephone
1 DURAND Jacques j.durand@orange.fr 16b rue brune 1 motdepass1 0601020304
2 DUVAL Paul paul.d@sfr.fr 135 avenue rouge 4 motdepass2 0704030201
3 DELORS Sophie sodelors@outlook.com 22a bd vert 3 motdepass3 0606060202
4 VERGER Jehan jverger@aol.com 4ter impasse jaune 5 motdepass4 0601020102
5 MONVILLE Fleur fleur1212@free.fr 9 sente aux loups 2 motdepass5 0707020201
6 BRIARD Paul paul.briard27@hotmail.fr 191 rue violette 4 motdepass6 0612345678
7 LÉGER Marguerite mag0506@perso.com 17 place noire 3 motdepass7 0687654321
8 FLAMAND Lise flise@gmail.com 329 route bleue 2 motdepass8 0632323232

Voici la requête qui répond à l'objectif visé :

SELECT idAdherent, UPPER(nomAdherent), UPPER(prenom)
FROM adherent
ORDER BY nomAdherent, prenom;

Le résultat suivant nous est restitué :

idAdherent nomMaj prenomMaj
6 BRIARD PAUL
3 DELORS SOPHIE
1 DURAND JACQUES
2 DUVAL PAUL
8 FLAMAND LISE
7 LEGER MARGUERITE
5 MONVILLE FLEUR
4 VERGER JEHAN

Nous savons maintenant effectuer, dans une requête, des calculs sur les colonnes et sur les lignes d'une table ou transformer une colonne, ainsi que trier le résultat d'une requête. Voyons maintenant quand et comment effectuer des requêtes portant sur plusieurs tables.

Requêtes portant sur plusieurs tables

Contexte d'une requête portant sur plusieurs tables

Dans une base de données existent quasi systématiquement des associations. Celles-ci établissent un lien entre des entités. Ainsi, pour retrouver des informations relatives à une même entité, on peut être amené à récupérer celles-ci dans plusieurs tables par le biais de ces associations.

bannière rappel

Rappel

Pou rappel, les tables adherent et ville sont constituées ainsi :

idAdherent nomAdherent prenom mail numero rue idVille passe telephone
1 DURAND Jacques j.durand@orange.fr 16b rue brune 1 motdepass1 0601020304
2 DUVAL Paul paul.d@sfr.fr 135 avenue rouge 4 motdepass2 0704030201
3 DELORS Sophie sodelors@outlook.com 22a bd vert 3 motdepass3 0606060202
4 VERGER Jehan jverger@aol.com 4ter impasse jaune 5 motdepass4 0601020102
5 MONVILLE Fleur fleur1212@free.fr 9 sente aux loups 2 motdepass5 0707020201
6 BRIARD Paul paul.briard27@hotmail.fr 191 rue violette 4 motdepass6 0612345678
7 LÉGER Marguerite mag0506@perso.com 17 place noire 3 motdepass7 0687654321
8 FLAMAND Lise flise@gmail.com 329 route bleue 2 motdepass8 0632323232

idVille nomVille codePostal
1 LE HAVRE 76600
2 CAEN 14000
3 NANTES 44000
4 RENNES 35000
5 QUIMPER 29000
6 VANNES 56000
7 SAINT-BRIEUC 22000
8 PONTIVY 56300
9 LOUDEAC 22600
10 QUIMPERLE 29300

Nous ne sommes pas en mesure de connaître, dans notre table adherent, le nom de la ville où chaque adhérent·e habite. Nous connaissons néanmoins le numéro d'identification, soit idVille, de la ville où chacun habite. Grâce à ce numéro, nous pouvons retrouver le nom de celle-ci dans une autre table : la table ville.

bannière exemple

Exemple

Ainsi, si nous souhaitons recueillir la liste des adhérent·e·s de notre club de cuisine, constituée de leur numéro d'identification, nom, prénom et ville où ils résident, nous sommes appelés à effectuer des recherches dans deux tables : adherent et ville.

Dans ce contexte où nous effectuons une requête portant sur plusieurs tables, une ambiguïté concernant la désignation de leurs colonnes respectives peut se présenter.

  • En effet, rien n'interdit de construire une base de données où un même nom de colonne peut figurer dans deux tables différentes.
bannière exemple

Exemple

Dans notre base de données, la table recette contient une colonne idRecette, tout comme la table etape.

bannière à retenir

À retenir

Aussi, pour lever toute ambiguïté dans une requête qui porterait sur des tables ayant des colonnes nommées de la même manière, il est alors nécessaire de préfixer le nom de la colonne par celui de la table concernée.

  • Finalement, on préfèrera, qu'il y ait ambiguïté ou non, préfixer tous les noms de colonnes du nom de la table à laquelle celles-ci appartiennent.
bannière exemple

Exemple

Dans notre exemple, ou désignera nos champs idRecette ainsi :

  • recette.idRecette ;
  • etape.idRecette ;

Et voici une requête utilisant un préfixe de nom de table :

SELECT recette.nomRecette, recette.categorie, recette.duree
FROM recette;

À l'usage, on réalise que ce préfixe peut alourdir considérablement la rédaction de certaines requêtes, déjà complexes par ailleurs.

  • On peut alors faire le choix de substituer le préfixe du nom de la table par un alias, plus court, qui sera précisé dans la commande SQL avec le mot-clé AS.

Notons que le recours à l'alias n'est pas obligatoire. ·

bannière exemple

Exemple

En affectant l’alias « re » pour notre table recette, la commande précédente est ainsi reformulée de façon plus compacte :

SELECT re.nomRecette, re.categorie, re.duree
FROM recette AS re;

Apprenons maintenant à formuler des requêtes portant sur plusieurs tables. Il s'agit de l'opération de jointure que nous allons dès à présent détailler.

La jointure interne

Dans le cas de la base de données de notre club de cuisine, pour obtenir la liste des adhérent·e·s constituée de leur numéro d'adhérent, leur nom, leur prénom et de la ville où ils résident, nous pourrions formaliser la requête suivante :

SELECT ad.idAdherent, ad.nomAdherent, ad.prenom, vi.nomVille
FROM adherent AS ad, ville AS vi
WHERE ad.idVille = vi.idVille

La logique de cette requête est tout à fait correcte. Le SGBD l’exécutera et donnera le résultat suivant :

idAdherent nomAdherent prenom nomVille
1 Durand Jacques LE HAVRE
2 Duval Paul RENNES
3 Delors Sophie NANTES
4 Verger Jehan QUIMPER
5 Monville Fleur CAEN
6 Briard Paul RENNES
7 Leger Marguerite NANTES
8 Flamand Lise CAEN
bannière attention

Attention

Cependant, il est nettement préférable d'avoir recours à un opérateur de jointure, nommé JOIN, spécifique aux requêtes portant sur plusieurs tables.

  • Le SGBD traitera alors la requête de manière optimisée.
bannière definition

Définition

Jointure :

Une jointure consiste à combiner des données issues de deux ou plusieurs tables, sur la base d'un point commun.

La syntaxe requise pour effectuer une jointure est la suivante, dans le cadre de notre exemple :

SELECT ad.idAdherent, ad.nomAdherent, ad.prenom, vi.nomVille
FROM adherent AS ad JOIN ville AS vi ON ad.idVille = vi.idVille;

Cette requête restituera le même résultat que précédemment, mais le SGBD aura optimisé les moyens de fournir ce résultat.
Notons par ailleurs qu'il est tout à fait possible de formaliser une requête ;SQL portant sur plus de deux tables.

bannière exemple

Exemple

Nous souhaitons avoir la liste des ingrédients de toutes les recettes, constituée de l'identifiant de la recette, du nom de la recette et du nom de l'ingrédient. La table utilise nous permet de savoir quelle recette utilise quel ingrédient. En revanche, dans cette table, les recettes sont identifiées par la clé idRecette, ce qui ne nous donne pas leur nom. Idem pour la clé idIngredient qui ne nous permet pas de connaître le nom des ingrédients.
Mais on peut retrouver le nom chaque recette dans la table recette avec la clé idRecette. De même, on retrouve le nom de chaque ingrédient dans la table ingredient avec la clé idIngredient.

Voici nos tables :

idIngredient idRecette quantite unite
1 1 1 jaune d’oeuf
1 2 3 oeufs entiers
1 4 3 oeufs entiers
2 1 1 cuillère
3 1 1 filet
4 1 10 cL
5 2 1 pincée
5 3 1 cuillère à café
5 4 1 pincee
5 7 1 pincée
6 2 2 tour de moulin
6 7 2 tours de moulin
7 2 30 g
8 2 2 cuillères à soupe
8 6 1 cuillère à soupe
8 7 2 cuillères à soupe
9 3 150 g
9 4 180 g
9 7 100 g
10 3 75 g
10 4 180 g
10 7 20 g
11 4 180 g
12 3 20 cL
13 5 500 g
14 5 150 g
15 5 2 pincées
16 5 1 pincée
17 6 1 poulet entier
18 7 2 branches
19 7 1 fruit entier
20 7 4 filets

idRecette nomRecette niveau duree categorie idAdherent
1 Mayonnaise difficile 15 sauce 7
2 Omelette facile 5 plat 6
3 Pâte brisée moyen 20 autre 6
4 Quatre-quarts facile 10 dessert 4
5 Purée de carottes moyen 15 accompagnement 2
6 Poulet rôti facile 15 plat 2
7 Sole meunière difficile 20 plat 7

idIngredient nomIngredient type
1 oeuf viande
2 moutarde condiment
3 vinaigre condiment
4 huile condiment
5 sel condiment
6 poivre condiment
7 gruyère râpé crèmerie
8 huile d’olive condiment
9 farine épicerie
10 beurre crèmerie
11 sucre épicerie
12 lait crèmerie
13 carotte légume
14 crème fraîche crémerie
15 cumin condiment
16 muscade condiment
17 poulet viande
18 persil condiment
19 citron fruit
20 sole viande

Nous pourrions rédiger la commande SQL suivante :

SELECT r.idRecette, r.nomRecette, i.nomIngredient
FROM utilise AS u, recette AS r, ingredient AS i
WHERE u.idRecette = r.idRecette AND u.idIngredient = i.idIngredient
ORDER BY r.idRecette, i.nomIngredient;

Mais le SGBD n'optimisera pas ses traitements pour restituer le résultat. Utilisons à nouveau une jointure avec le mot-clé JOIN :

SELECT r.idRecette, r.nomRecette, i.nomIngredient
FROM utilise AS u JOIN recette AS r JOIN ingredient AS i ON (u.idRecette = r.idRecette) AND (u.idIngredient = i.idIngredient)
ORDER BY r.idRecette, i.nomIngredient;

Le résultat de ces deux commandes sera identique :

idRecette nomRecette nomIngredient
1 Mayonnaise huile
1 Mayonnaise moutarde
1 Mayonnaise oeuf
1 Mayonnaise vinaigre
2 Omelette gruyère râpé
2 Omelette huile d’olive
2 Omelette oeuf
2 Omelette poivre
2 Omelette sel
3 Pâte brisée beurre
3 Pâte brisée farine
3 Pâte brisée lait
3 Pâte brisée sel
4 Quatre-quarts beurre
4 Quatre-quarts farine
4 Quatre-quarts oeuf
4 Quatre-quarts sel
4 Quatre-quarts sucre
5 Purée de carottes carotte
5 Purée de carottes crème fraîche
5 Purée de carottes cumin
5 Purée de carottes muscade
6 Poulet rôti huile d’olive
6 Poulet rôti poulet
7 Sole meunière beurre
7 Sole meunière citron
7 Sole meunière farine
7 Sole meunière huile d’olive
7 Sole meunière persil
7 Sole meunière poivre
7 Sole meunière sel
7 Sole meunière sole

La jointure externe

La jointure externe permet d’effectuer une jointure en incluant les lignes dont la clé étrangère qui fait le lien entre deux tables n’est pas renseignée. Sachant que deux tables sont considérées dans cette jointure, il faut préciser laquelle des deux servira de référence.
Ainsi, toutes les lignes de la table qui servira de référence seront représentées dans la table résultat. L’attribut ou les attributs récupérés via la clé étrangère seront renseignés avec la valeur trouvée dans la seconde table, ou renseignée à « NULL » lorsque la clé étrangère n’est pas renseignée dans la première table.

bannière à retenir

À retenir

Il faudra employer pour cela la clause OUTER JOIN.

bannière exemple

Exemple

On souhaite avoir la liste des adhérent·e·s constituée de leur numéro d’identification, leur nom, leur prénom, l’identifiant et le nom de chaque recette rédigée par un adhérent donné.

On passera la commande suivante :

SELECT a.idAdherent, a.nomAdherent, a.prenom, r.idRecette, r.nomRecette
FROM adherent AS a JOIN recette AS r ON a.idAdherent = r.idAdherent
ORDER BY a.idAdherent, r.nomRecette;

bannière rappel

Rappel

Pour rappel, les tables concernées sont constituées comme suit :

idRecette nomRecette niveau duree categorie idAdherent
1 Mayonnaise difficile 15 sauce 7
2 Omelette facile 5 plat 6
3 Pâte brisée moyen 20 autre 6
4 Quatre-quarts facile 10 dessert 4
5 Purée de carottes moyen 15 accompagnement 2
6 Poulet rôti facile 15 plat 2
7 Sole meunière difficile 20 plat 7

idAdherent nomAdherent prenom mail numero rue idVille passe telephone
1 DURAND Jacques j.durand@orange.fr 16b rue brune 1 motdepass1 0601020304
2 DUVAL Paul paul.d@sfr.fr 135 avenue rouge 4 motdepass2 0704030201
3 DELORS Sophie sodelors@outlook.com 22a bd vert 3 motdepass3 0606060202
4 VERGER Jehan jverger@aol.com 4ter impasse jaune 5 motdepass4 0601020102
5 MONVILLE Fleur fleur1212@free.fr 9 sente aux loups 2 motdepass5 0707020201
6 BRIARD Paul paul.briard27@hotmail.fr 191 rue violette 4 motdepass6 0612345678
7 LÉGER Marguerite mag0506@perso.com 17 place noire 3 motdepass7 0687654321
8 FLAMAND Lise flise@gmail.com 329 route bleue 2 motdepass8 0632323232

On obtient :

idAdherent nomAdherent prenom idRecette nomRecette
2 Duval Paul 6 Poulet rôti
2 Duval Paul 5 Purée de carottes
4 Verger Jehan 4 Quatre-quarts
6 Briard Paul 2 Omelette
6 Briard Paul 3 Pâte brisée
7 Leger Marguerite 1 Mayonnaise
7 Leger Marguerite 7 Sole meunière

Mais nous souhaiterions que cette liste d’adhérent·e·s n’exclue pas ceux qui n’ont rédigé aucune recette. Pour cela, il faut faire appel à une jointure externe, en prenant adherent comme table de référence.
La commande SQL qui correspond se formalise ainsi :

SELECT a.idAdherent, a.nomAdherent, a.prenom, r.idRecette, r.nomRecette
FROM adherent AS a LEFT OUTER JOIN recette AS r ON a.idAdherent = r.idAdherent
ORDER BY a.idAdherent, r.nomRecette;

LEFT indique que c’est la table qui apparaît à gauche dans la clause FROM qui sert de référence.
Ce qui veut dire que la commande qui suit est identique à la précédente :

SELECT a.idAdherent, a.nomAdherent, a.prenom, r.idRecette, r.nomRecette
FROM adherent AS a RIGHT OUTER JOIN recette AS r ON a.idAdherent = r.idAdherent
ORDER BY a.idAdherent, r.nomRecette;

Et le résultat obtenu est le suivant :

idAdherent nomAdherent prenom idRecette nomRecette
1 Durand Jacques NULL NULL
2 Duval Paul 6 Poulet rôti
2 Duval Paul 5 Purée de carottes
3 Delors Sophie NULL NULL
4 Verger Jehan 4 Quatre-quarts
5 Monville Fleur NULL NULL
6 Briard Paul 2 Omelette
6 Briard Paul 3 Pâte brisée
7 Leger Marguerite 1 Mayonnaise
7 Leger Marguerite 7 Sole meunière
8 Flamand Lise NULL NULL

Prenons maintenant la table recette en référence en inscrivant la commande :

SELECT a.idAdherent, a.nomAdherent, a.prenom, r.idRecette, r.nomRecette
FROM adherent AS a RIGHT OUTER JOIN recette AS r ON a.idAdherent = r.idAdherent
ORDER BY a.idAdherent, r.nomRecette;

On obtient alors :

idAdherent nomAdherent prenom idRecette nomRecette
2 Duval Paul 6 Poulet rôti
2 Duval Paul 5 Purée de carottes
4 Verger Jehan 4 Quatre-quarts
6 Briard Paul 2 Omelette
6 Briard Paul 3 Pâte brisée
7 Leger Marguerite 1 Mayonnaise
7 Leger Marguerite 7 Sole meunière

Comme voulu, toutes les lignes de la table recette sont représentées dans la table résultat. Notons que l’on n’observe aucune colonne nulle (« NULL ») parmi les lignes de la table résultat. Cette particularité est due au fait que toute recette est forcément rédigée par un·e adhérent·e. L’inverse n’étant pas vrai, on l’a vu précédemment : tout adhérent n’a pas forcément rédigé une recette.

Pour terminer, on peut tenter de combiner différentes clauses. Si nous souhaitons par exemple connaître tous les adhérent·e·s qui n’ont pas proposé de recette, il suffira de passer la commande SQL suivante :

SELECT a.idAdherent, a.nomAdherent, a.prenom, r.idRecette, r.nomRecette
FROM recette AS r RIGHT OUTER JOIN adherent AS a ON a.idAdherent = r.idAdherent
WHERE r.idRecette IS NULL;

Ce qui donnera le résultat escompté, à savoir :

idAdherent nomAdherent prenom idRecette nomRecette
1 Durand Jacques NULL NULL
3 Delors Sophie NULL NULL
5 Monville Fleur NULL NULL
8 Flamand Lise NULL NULL

Conclusion :

Nous achevons ainsi ce cours donnant des notions complémentaires sur le langage SQL. Vous savez dorénavant rédiger des requêtes élaborées, faisant appel à des mécanismes de calcul, de regroupement, de transformation, de tri ou encore de jointure.