Aller au contenu

Chapitre 3 : Fusion de tables

Programme officiel (B.O.)

B.O. spécial n° 1 du 22 janvier 2019 - NSI Première

Contenus Capacités attendues Commentaires
Fusion de tables Construire une nouvelle table en combinant les données de deux tables. La notion de clé étrangère est mise en évidence.

1. Pourquoi fusionner des tables ?

1.1 Le problème de la redondance

Imaginons qu'on veuille stocker les résultats des élèves avec les informations de leur classe. Si on met tout dans une seule table, les informations de classe sont répétées pour chaque élève :

Nom Classe Professeur principal Salle Note
Dupont 1NSI-A M. Duval 204 15
Martin 1NSI-A M. Duval 204 12
Durand 1NSI-B Mme Leroux 108 18
Petit 1NSI-A M. Duval 204 9

Les informations « M. Duval » et « 204 » sont répétées trois fois. C'est de la redondance.

1.2 La solution : séparer les données

On sépare en deux tables reliées par un attribut commun (la clé) :

Table eleves :

Nom Classe Note
Dupont 1NSI-A 15
Martin 1NSI-A 12
Durand 1NSI-B 18
Petit 1NSI-A 9

Table classes :

Classe Professeur principal Salle
1NSI-A M. Duval 204
1NSI-B Mme Leroux 108

L'attribut Classe est présent dans les deux tables : c'est la clé de jointure. Dans la table eleves, on l'appelle clé étrangère car elle fait référence à une entrée d'une autre table.


2. La jointure

2.1 Principe

La jointure (ou fusion) consiste à combiner les lignes de deux tables qui partagent une même valeur pour un attribut commun.

Pour chaque ligne de la première table, on cherche la ligne correspondante dans la seconde table (celle qui a la même valeur de clé), et on fusionne les deux.

2.2 Exemple en Python

eleves = [
    {"nom": "Dupont", "classe": "1NSI-A", "note": 15},
    {"nom": "Martin", "classe": "1NSI-A", "note": 12},
    {"nom": "Durand", "classe": "1NSI-B", "note": 18},
    {"nom": "Petit",  "classe": "1NSI-A", "note": 9}
]

classes = [
    {"classe": "1NSI-A", "prof": "M. Duval", "salle": 204},
    {"classe": "1NSI-B", "prof": "Mme Leroux", "salle": 108}
]

def jointure(table1, table2, cle):
    """Fusionne deux tables sur un attribut commun."""
    resultat = []
    for ligne1 in table1:
        for ligne2 in table2:
            if ligne1[cle] == ligne2[cle]:
                fusion = {}
                fusion.update(ligne1)
                fusion.update(ligne2)
                resultat.append(fusion)
    return resultat

table_complete = jointure(eleves, classes, "classe")
for e in table_complete:
    print(e)

Résultat :

{"nom": "Dupont", "classe": "1NSI-A", "note": 15, "prof": "M. Duval", "salle": 204}
{"nom": "Martin", "classe": "1NSI-A", "note": 12, "prof": "M. Duval", "salle": 204}
{"nom": "Durand", "classe": "1NSI-B", "note": 18, "prof": "Mme Leroux", "salle": 108}
{"nom": "Petit",  "classe": "1NSI-A", "note": 9,  "prof": "M. Duval", "salle": 204}

2.3 Fonctionnement détaillé

Pour chaque élève, on parcourt toutes les classes pour trouver celle qui a la même valeur de "classe". Quand on la trouve, on fusionne les deux dictionnaires :

Dupont (1NSI-A) + classe 1NSI-A (M. Duval, 204) → fusion
Martin (1NSI-A) + classe 1NSI-A (M. Duval, 204) → fusion
Durand (1NSI-B) + classe 1NSI-B (Mme Leroux, 108) → fusion
Petit  (1NSI-A) + classe 1NSI-A (M. Duval, 204) → fusion

3. Cas particuliers

3.1 Lignes sans correspondance

Si un élève a une classe qui n'existe pas dans la table classes, il ne sera pas inclus dans le résultat de la jointure :

eleves = [
    {"nom": "Dupont", "classe": "1NSI-A", "note": 15},
    {"nom": "Moreau", "classe": "1NSI-C", "note": 14}  # classe inconnue
]

# Moreau n'apparait pas dans le résultat car "1NSI-C" n'est pas dans classes

C'est le comportement standard de la jointure : seules les lignes ayant une correspondance dans les deux tables sont conservées.

3.2 Attributs en conflit

Si les deux tables ont un attribut de même nom (autre que la clé), la valeur de la seconde table écrase celle de la première (avec update()). Pour l'éviter, on peut renommer les attributs :

def jointure_safe(table1, table2, cle):
    """Jointure avec préfixe pour éviter les conflits."""
    resultat = []
    for l1 in table1:
        for l2 in table2:
            if l1[cle] == l2[cle]:
                fusion = {}
                for k, v in l1.items():
                    fusion[k] = v
                for k, v in l2.items():
                    if k != cle:
                        fusion[k] = v
                resultat.append(fusion)
    return resultat

4. Clé primaire et clé étrangère

4.1 Clé primaire

Une clé primaire est un attribut (ou un ensemble d'attributs) qui identifie de manière unique chaque ligne d'une table. Aucune autre ligne ne peut avoir la même valeur.

Dans la table classes, "classe" est la clé primaire : chaque classe n'apparait qu'une seule fois.

4.2 Clé étrangère

Une clé étrangère est un attribut d'une table qui fait référence à la clé primaire d'une autre table.

Dans la table eleves, "classe" est une clé étrangère : elle fait référence à la clé primaire de la table classes.

Table eleves                    Table classes
+---------+---------+------+    +---------+------------+-------+
| nom     | classe  | note |    | classe  | prof       | salle |
+---------+---------+------+    +---------+------------+-------+
| Dupont  | 1NSI-A ------>|    | 1NSI-A  | M. Duval   | 204   |
| Martin  | 1NSI-A ------>|    | 1NSI-B  | Mme Leroux | 108   |
| Durand  | 1NSI-B ------>|    +---------+------------+-------+
| Petit   | 1NSI-A ------>|
+---------+---------+------+

4.3 Intérêt

  • Pas de redondance : les informations de chaque classe ne sont stockées qu'une seule fois.
  • Cohérence : si le prof principal change, on ne modifie qu'une seule ligne dans classes (et non toutes les lignes de eleves).
  • Organisation : les données sont séparées par thème logique.

5. Exemple complet : combiner trois tables

On peut enchaîner les jointures pour fusionner plus de deux tables :

eleves = [
    {"id_eleve": 1, "nom": "Dupont", "id_classe": 101},
    {"id_eleve": 2, "nom": "Martin", "id_classe": 101},
    {"id_eleve": 3, "nom": "Durand", "id_classe": 102}
]

classes = [
    {"id_classe": 101, "nom_classe": "1NSI-A", "id_prof": 201},
    {"id_classe": 102, "nom_classe": "1NSI-B", "id_prof": 202}
]

professeurs = [
    {"id_prof": 201, "nom_prof": "M. Duval"},
    {"id_prof": 202, "nom_prof": "Mme Leroux"}
]

# Étape 1 : fusionner élèves et classes
etape1 = jointure(eleves, classes, "id_classe")

# Étape 2 : fusionner le résultat avec les professeurs
resultat = jointure(etape1, professeurs, "id_prof")

for e in resultat:
    print(f"{e['nom']} - {e['nom_classe']} - {e['nom_prof']}")
# Dupont - 1NSI-A - M. Duval
# Martin - 1NSI-A - M. Duval
# Durand - 1NSI-B - Mme Leroux

6. Résumé

Concept Détail
Redondance Répétition inutile d'informations dans une table
Jointure Fusion de deux tables sur un attribut commun
Clé primaire Attribut identifiant de manière unique chaque ligne
Clé étrangère Attribut faisant référence à la clé primaire d'une autre table
Algorithme Double boucle : pour chaque ligne de T1, chercher la correspondance dans T2
Sans correspondance Les lignes sans correspondance sont exclues du résultat