%% nav-debut : généré par gen_navigation.py, ne pas modifier à la main %% > [!nav] > ↩ [[Code et Développement/Développement d'Applications/SQL I/SQL I|Accueil · SQL I]] > > | [[Code et Développement/Développement d'Applications/SQL I/05_Comment répondre à une demande\|← Comment répondre à une demande]] | [[Code et Développement/Développement d'Applications/SQL I/07_Fonctions utiles\|Fonctions utiles →]] | > |:---|---:| %% nav-fin %% [[05_Comment répondre à une demande|Comment répondre à une demande]] # Généralisation : requêtes sur n tables Lors de vos traitements de données, il ne sera pas rare de devoir faire une requête, non pas sur une ou deux tables, mais bien sur trois, quatre tables, voire plus. Et comme toujours, il sera primordial de savoir à quoi correspondra un enregistrement qui sort du `FROM`. Pour comprendre le principe, nous vous proposons de regarder la vidéo ci-dessous. Cette vidéo vous parle des différents cas où l'on utilise 3 tables, puis généralise à n tables. <iframe width="560" height="315" src="https://www.youtube.com/embed/oRlhZ9B3C30?si=etm_IsGIrg8WK8Ux" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> ## Ce qu'il faut retenir Avec plusieurs tables, la question reste la même : **à quoi correspond un enregistrement en sortie du `FROM` ?** La réponse dépend de la façon dont les tables sont reliées par leurs clés étrangères. Dans ce qui suit, « B → A » signifie : *la table B contient une clé étrangère vers la table A*. ### Les 4 cas avec 3 tables > [!example] Cas 1 : les tables s'enchaînent (A ← B ← C) > B contient une clé étrangère vers A, et C contient une clé étrangère vers B. > > Un enregistrement en sortie du `FROM` correspond à **un enregistrement de C**, la table au bout de la chaîne. B et A apportent des informations complémentaires. > > *Exemple : une épreuve (C) appartient à une catégorie (B), qui appartient à un type de catégorie (A). Un enregistrement est une épreuve.* > [!example] Cas 2 : une table au centre (A ← B → C) > B contient une clé étrangère vers A **et** une clé étrangère vers C. > > Un enregistrement en sortie du `FROM` correspond à **un enregistrement de B**, la table du centre. A et C apportent des informations complémentaires. > > *Exemple : une épreuve (B) concerne un sport (A) et une catégorie (C). Un enregistrement est une épreuve.* > [!danger] Cas 3 : deux tables pointent vers la même table (A → B ← C) > A et C contiennent toutes les deux une clé étrangère vers B. > > Pour un enregistrement de B, la jointure associe **chaque** enregistrement de A à **chaque** enregistrement de C : c'est un produit cartésien entre les deux jointures. Un enregistrement en sortie du `FROM` **ne correspond à rien d'utilisable**, et les comptages ou les sommes seront faux. > > *Exemple : un client (B) a des commandes (A) et des factures (C). Un client avec 3 commandes et 2 factures donne 3 × 2 = 6 lignes.* > > 👉 Il faut **décomposer le travail en plusieurs requêtes** : une requête par jointure, puis une requête qui assemble les résultats. > [!example] Cas 4 : une jointure et un produit cartésien > A et B sont reliées par une jointure, et C n'a aucun lien avec elles. > > Chaque enregistrement issu de la jointure A–B est combiné avec chaque enregistrement de C. C'est utile quand C ne contient **qu'un seul enregistrement** : on ajoute alors simplement cette valeur à chaque ligne. > > *Exemple : la moyenne des chiffres d'affaires ajoutée à chaque client dans le chapitre [[Code et Développement/Développement d'Applications/SQL I/05_Comment répondre à une demande|Comment répondre à une demande]].* ### Généralisation à n tables Quel que soit le nombre de tables, on applique la même méthode : 1. Repérez sur le schéma relationnel le sens de chaque clé étrangère. 2. Identifiez la table d'où partent toutes les clés étrangères (au bout de la chaîne ou au centre) : un enregistrement en sortie du `FROM` correspond à cette table. 3. Si deux tables pointent vers la même table (cas 3), il n'y a pas de réponse : décomposez le travail en plusieurs requêtes. ### Exemple avec 4 tables ![[Code et Développement/Développement d'Applications/SQL I/ressources/schema_epreuves.png]] Ici, `EPREUVE` → `SPORT`, `EPREUVE` → `CATEGORIE` et `CATEGORIE` → `TYPE CATEGORIE`. Toutes les clés étrangères partent de `EPREUVE` (cas 1 et 2 combinés) : **un enregistrement en sortie du `FROM` est une épreuve**. **Demande 1 : nombre d'épreuves par sport et par type de catégorie.** Un enregistrement étant une épreuve, il suffit de regrouper par sport et par type de catégorie, puis de compter les épreuves. **Une seule requête suffit.** > [!tip]- Voir une solution > ```sql > SELECT c.ref_nom_type_categorie, s.nom_sport, COUNT(e.id_epreuve) AS nb_epreuves > FROM EPREUVE e INNER JOIN SPORT s ON e.ref_sport = s.id_sport > INNER JOIN CATEGORIE c ON e.ref_categorie = c.id_categorie > GROUP BY c.ref_nom_type_categorie, s.nom_sport; > ``` > La table `TYPE CATEGORIE` n'est pas nécessaire : le nom du type est déjà présent dans `CATEGORIE` (`ref_nom_type_categorie`). **Demande 2 : nombre de sports par type de catégorie.** Le piège : un enregistrement est toujours **une épreuve**, pas un sport. Un même sport possède souvent plusieurs épreuves dans un même type de catégorie (par exemple le judo en -15 ans **et** en -17 ans, deux catégories de type « Age »). Compter directement les sports reviendrait donc à compter les épreuves, et le résultat serait trop grand. Il faut **deux requêtes** : 1. Une première requête qui donne la liste des couples (type de catégorie, sport), chaque couple n'apparaissant qu'une fois. 2. Une deuxième requête qui compte, pour chaque type de catégorie, le nombre de sports dans cette liste. > [!tip]- Voir une solution > ```sql > SELECT ref_nom_type_categorie, COUNT(ref_sport) AS nb_sports > FROM ( > SELECT c.ref_nom_type_categorie, e.ref_sport > FROM EPREUVE e INNER JOIN CATEGORIE c ON e.ref_categorie = c.id_categorie > GROUP BY c.ref_nom_type_categorie, e.ref_sport > ) R2 > GROUP BY ref_nom_type_categorie; > ``` > La requête intérieure utilise un `GROUP BY` pour ne garder qu'une ligne par couple (type, sport) : chaque sport n'est alors compté qu'une fois par type de catégorie. --- Pour certaines demandes, vous aurez besoin de fonctions (calculs, dates, textes, conditions). Elles sont regroupées dans la page [[Code et Développement/Développement d'Applications/SQL I/07_Fonctions utiles|Fonctions utiles]]. %% nav-debut : généré par gen_navigation.py, ne pas modifier à la main %% > [!nav] > ↩ [[Code et Développement/Développement d'Applications/SQL I/SQL I|Accueil · SQL I]] > > | [[Code et Développement/Développement d'Applications/SQL I/05_Comment répondre à une demande\|← Comment répondre à une demande]] | [[Code et Développement/Développement d'Applications/SQL I/07_Fonctions utiles\|Fonctions utiles →]] | > |:---|---:| %% nav-fin %% --- 🗓️ Historique Dernière mise à jour : `21 octobre 2026` Rédigé par : [[Vincent TELLIER]]