Aller au contenu

Fusionner des tables

Les exercices de cette page sont plus complexes: ils font appel à tout ce qui a été vu auparavant pour exploiter des données venant de plusieurs tables de données.

Ce type de fusion doit être maîtrisé.

Note

Ce type de travail sera prolongé en terminale avec l'étude du langage SQL.

Des clients et leurs commandes

On dispose d'un fichier client.csv

Contenu de client.csv

id_client nom prénom
1 Bagou Albert
2 Charabia Barnabé
3 Blabla Casimir
4 Paulitik Zoé
5 Escro Virgil
6 Manteux Rémi

et d'un fichier commande.csv.

Contenu de commande.csv

Le champ id_client fait référence au champ de même nom du fichier client.

Par exemple, la commande ayant l'id_commande égal à 1 a été faite par la personne id_client = 2, c'est à dire par Charabia Barnabé.

id_commande id_client descriptif
1 2 bouilloire
2 3 Livre Apprende Python
3 2 Livre   Apprendre HTML
4 4 livre   Apprendre CSS
5 6 couverture
6 4 VTT
7 4 smartphone
8 1 cahiers
9 2 Livre Le réseau internet
10 3 Livre Les systèmes d’exploitation
11 1 livre   Algorithmique

Fusion

On aimerait les fusionner. Plus précisément, on vous demande de construire une liste de dictionnaires dans laquelle chaque dictionnaire se présente ainsi:

{'id_client': ..., 'nom': ..., 'prénom': ..., 'id_commande': ..., 'descriptif': ...}.

Bien sûr dans cette ligne, la commande doit avoir été faite par le client, ce qui signifie que l'identifiant client de la commande est bien l'identifiant du client correspondant aux nom et prénom obtenus.

Un client qui n'a pas fait de commande n'apparaîtra pas dans cette liste.

Solution
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import csv


def de_csv_vers_dico(fichier):
    """
    fichier -- nom d'un fichier csv (sans l'extension) 

    renvoie la liste de dictionnaires associée au fichier.
    """
    with open(fichier + '.csv', newline='') as fichiercsv:
        lecture = csv.DictReader(fichiercsv, delimiter=',')
        return [ligne for ligne in lecture]


# lecture des deux tables et stockage dans des listes:
clients = de_csv_vers_dico('client')
commandes = de_csv_vers_dico('commande')


# création de la liste fusion:
liste = []
for commande in commandes:
    for client in clients:
        if commande['id_client'] == client['id_client']:
            dico = {'id_client': client['id_client'],
                    'nom': client['nom'],
                    'prénom': client['prénom'],
                    'id_commande': int(commande['id_commande']), # transfo en entier pour le tri
                    'descriptif': commande['descriptif']                    
            }
            liste.append(dico)

# A vous de visualiser le résultat avec des appels à la fonction print

Tri de la fusion

Ordonnez la liste obtenue après fusion suivant l'ordre croissant des noms des clients et pour un même client suivant l'ordre croissant des id_commande.

Solution
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import csv


def de_csv_vers_dico(fichier):
    """
    fichier -- nom d'un fichier csv (sans l'extension) 

    renvoie la liste de dictionnaires associée au fichier.
    """
    with open(fichier + '.csv', newline='') as fichiercsv:
        lecture = csv.DictReader(fichiercsv, delimiter=',')
        return [ligne for ligne in lecture]


# lecture des deux tables et stockage dans des listes:
clients = de_csv_vers_dico('client')
commandes = de_csv_vers_dico('commande')


# création de la liste fusion:
liste = []
for commande in commandes:
    for client in clients:
        if commande['id_client'] == client['id_client']:
            dico = {'id_client': client['id_client'],
                    'nom': client['nom'],
                    'prénom': client['prénom'],
                    'id_commande': int(commande['id_commande']), # transfo en entier pour le tri
                    'descriptif': commande['descriptif']                    
            }
            liste.append(dico)


# on trie le résultat suivant l'ordre imposé dans l'énoncé:
liste.sort(key= lambda x:x['id_commande'])
liste.sort(key= lambda x:x['nom'])

# A vous de visualiser le résultat avec des appels à la fonction print

Stokage du résultat dans un fichier

Avec la liste obtenue par fusion, vous créerez un fichier csv, en utilisant DictWriter. Il vous faudra commencer par lire la documentation associée.

Code pour créer le fichier avec dictionnaires

Une fonction pour créer un fichier csv à partir d'une liste de dictionnaires (présentant les mêmes champs).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
def de_dico_vers_csv(liste, nomFichier):
    """
    liste -- liste de dictionnaires
    nomFichier -- nom du fichier à créer (sans extension)

    crée le fichier csv contenant les contenus des dictionnaires 
    """
    # création et ouverture en écriture:
    with open(nomFichier + '.csv', 'w', newline='') as fichiercsv:

        # création de la ligne d'entête (noms des colonnes):
        entete = [clef for clef in liste[0].keys()]

        ecriture = csv.DictWriter(fichiercsv, fieldnames=entete)
        ecriture.writeheader()
        # écriture  des dictionnaires de la liste dans le fichier:
        for ligne in liste:
            ecriture.writerow(ligne)
Solution
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import csv


def de_csv_vers_dico(fichier):
    """
    fichier -- nom d'un fichier csv (sans l'extension) 

    renvoie la liste de dictionnaires associée au fichier.
    """
    with open(fichier + '.csv', newline='') as fichiercsv:
        lecture = csv.DictReader(fichiercsv, delimiter=',')
        return [ligne for ligne in lecture]



def de_dico_vers_csv(liste, nomFichier):
    """
    liste -- liste de dictionnaires
    nomFichier -- nom du fichier créé (sans extension)

    crée le fichier csv contenant les contenus des dictionnaires 
    """
    with open(nomFichier + '.csv', 'w', newline='') as fichiercsv:
        entete = [clef for clef in liste[0].keys()]
        ecriture = csv.DictWriter(fichiercsv, fieldnames=entete)
        ecriture.writeheader()
        for ligne in liste:
            ecriture.writerow(ligne)




# lecture des deux tables et stockage dans des listes:
clients = de_csv_vers_dico('client')
commandes = de_csv_vers_dico('commande')


# création de la liste  fusion:
liste = []
for commande in commandes:
    for client in clients:
        if commande['id_client'] == client['id_client']:
            dico = {'id_client': client['id_client'],
                    'nom': client['nom'],
                    'prénom': client['prénom'],
                    'id_commande': int(commande['id_commande']), # transfo en entier pour le tri
                    'descriptif': commande['descriptif']                    
            }
            liste.append(dico)


# on trie le résultat suivant l'ordre imposé dans l'énoncé:
liste.sort(key= lambda x:x['id_commande'])
liste.sort(key= lambda x:x['nom'])

# on lance la création du fichier csv pour stockage du résultat:
de_dico_vers_csv(liste, 'clients_commandes')

Le fichier obtenu

Des enseignants et leurs cours

On utilise dans cet exercice la table personnes.csv et la table cours.csv

la table personnes

id_personne nom prenom anneeNaissance
1 Labrosse Adam 2000
2 Gemlamorte Adèle 1985
3 Auboisdormant Abel 2001
4 Etpan Ahmed 1975
5 Térieur Alain 1999
6 Térieur Alex 1976
7 Proviste Alain 2000
8 Verse Alain 1970
9 Ception Alex 2001
10 Ainé Ali 1975
11 Gator Ali 2001
12 Bistraux Alonzo 2001
13 Patamob Alphonse 1970
14 Ficulté Andy 1980
15 Rectdustade Andy 2000
16 Verserre Annie 2001
17 Boréal Aurore 1985
18 Nor Paul 1985
19 Dejeu Bernadette 2001
20 Dajeun Bruno 1984
21 Hiple Candice 2000

la table cours

La colonne id_enseignant fait référence à la colonne id_personne de la table personnes.

Ainsi on sait, par exemple, que le cours sur la théorie des graphes est assuré par Adèle Gemlamorte.

id_cours id_enseignant intitule
1 2 théorie des graphes
2 4 programmation objet
3 6 programmation fonctionnelle
4 8 théorie des automates
5 10 base de données relationnelle
6 13 réseaux
7 14 langage python
8 17 html et css
9 18 javascript
10 20 java
11 2 algorithmique
12 4 tests logiciels
13 6 intelligence artificielle
14 8 UML
15 10 XML
16 13 scheme
17 14 merise
18 14 webgl
19 Unix

Vous devez créer une liste de dictionnaires. Les clefs de chaque dictionnaire seront 'id_personne', 'nom', 'prenom', 'id_cours', 'intitule'. Cette liste met donc en face de chaque personne les cours qu'elle assure.

Chaque personne devra apparaître dans la liste même si elle n'assure pas de cours ('id_cours' et 'intitule' seront dans ce cas associées à '').

Une personne assurant plusieurs cours apparaît sur autant de lignes...

Un cours qui n'est assuré par personne devra aussi apparaître (avec '' pour valeur associée aux clefs identifiant l'enseignant).

La liste devra être triée suivant le nom des personnes (ordre croissant). Et pour une même personne, les lignes seront triées suivant le nom des cours (ordre croissant).

La liste créée sera envoyée dans un fichier csv.

Solution
import csv


def de_csv_vers_dico(fichier):
    """
    fichier -- nom d'un fichier csv (sans l'extension) 

    renvoie la liste de dictionnaires associée au fichier.
    """
    with open(fichier + '.csv', newline='') as fichiercsv:
        lecture = csv.DictReader(fichiercsv, delimiter=',')
        return [ligne for ligne in lecture]



def de_dico_vers_csv(liste, nomFichier):
    """
    liste -- liste de dictionnaires
    nomFichier -- nom du fichier créé (sans extension)

    crée le fichier csv contenant les contenus des dictionnaires 
    """
    with open(nomFichier + '.csv', 'w', newline='') as fichiercsv:
        entete = [clef for clef in liste[0].keys()]
        ecriture = csv.DictWriter(fichiercsv, fieldnames=entete)
        ecriture.writeheader()
        for ligne in liste:
            ecriture.writerow(ligne)





personnes = de_csv_vers_dico('personnes')
cours = de_csv_vers_dico('cours')

# premier parcours, on associe enseignant et cours
liste = []
for discipline in cours:
    for personne in personnes:
        if discipline['id_enseignant'] == personne['id_personne']:
            dico = {'id_personne': personne['id_personne'],
                    'nom': personne['nom'],
                    'prenom': personne['prenom'],
                    'id_cours': discipline['id_cours'],
                    'intitule': discipline['intitule']
            }
            liste.append(dico)



# seconde boucle, on ajoute les personnes ne donnant pas de cours
for personne in personnes:
    present = False
    for dico in liste:
        if personne['id_personne'] == dico['id_personne']:
            present = True
    if not present:
        liste.append({'id_personne': personne['id_personne'],
                    'nom': personne['nom'],
                    'prenom': personne['prenom'],
                    'id_cours': '',
                    'intitule': ''}
                    )


# troisième boucle, on ajoute les cours n'ayant pas d'enseignant
for crs in cours:
    present = False
    for dico in liste:
        if crs['id_cours'] == dico['id_cours']:
            present = True
    if not present:
        liste.append({'id_personne': '',
                    'nom': '',
                    'prenom': '',
                    'id_cours': crs['id_cours'],
                    'intitule': crs['intitule']}
                    )



# on trie:
liste.sort(key= lambda x:x['intitule'])
liste.sort(key= lambda x:x['nom'])


de_dico_vers_csv(liste, 'enseignements')

Fichier csv obtenu

Remarque sur le tri

L'ordre des lettres est l'ordre ASCII, les majuscules sont situées avant les minuscules, ce qui explique que par exemple pour Ali Ainé, le cours XML soit placé avant le cours 'base de données relationnelle'.
Pour règler ce problème, il suffit de trier suivant les chaînes préalablement toutes passées en minuscule, ce qui se fait facilement avec la méthode lower en remplaçant les deux lignes de tris par:

liste.sort(key= lambda x:x['intitule'].lower())
liste.sort(key= lambda x:x['nom'].lower())
Fichier csv obtenu

Des acteurs et leurs rôles

On utilise ici trois tables:

la table personna

id_personne nom prenom
1 Brasseur Claude
2 Boon Dany
3 Goldblum Jeff
4 Reno Jean
5 Balasko Josiane
6 Olivares Gerardo
7 Emmerich Roland
8 Kidmann Nicole
9 Kubrick Stanley
10 Cruise Tom
11 McQuarrie Christopher
12 Spielberg Steven
13 Ford Harrison
14 Abrams JJ
15 Merad Kad
16 Rich Claude
17 Tavernier Bertrand
18 Robert Yves
19 Berri Claude
20 Aghion Gabriel
21 Darmon Gérard
22 Laroque Michèle

la table joue

id_acteur fait référence à l'id_personne de la table personna. id_film fait référence à l'id_film de la table film.

Ainsi, on sait que Nicole Kidmann (id_personne = 8) joue le rôle d'Alice (id_role = 1) dans "Eyes Wide Shut" (id_film = 1).

id_role id_acteur id_film role
1 8 1 Alice
2 10 1 Bill
3 10 2 Ethan Hunt
4 10 3 John Anderton
5 13 6 Indiana Jones
6 13 7 Han Solo
7 2 8 Antoine Bailleul
8 15 8 Philippe Abrams
9 16 9 Duc Clovis de Crassac
10 1 10 Daniel
11 2 11 Seb
12 21 11 Loïc
13 22 11 Marie Hagutte

la table film

id_realisateur fait référence à id_personne de la table personna.

id_film id_realisateur titre genre annee
1 9 Eyes Wide Shut drame 1999
2 11 Mission impossible 5 action 2015
3 12 Minority Report SF 2002
4 12 Les dents de la mer épouvante 1975
5 12 E.T. l'extraterrestre SF 1982
6 12 Les aventuriers de l'Arche perdue aventure 1981
7 14 Star Wars - Le Réveil de la Force SF 2015
8 2 Bienvenue chez les Ch'tis comédie 2008
9 17 La fille de D'Artagnan cape et épée 1994
10 18 Un éléphant, ça trompe énormément comédie 1976
11 20 Pédale dure comédie 2004

Créer une liste de dictionnaires présentant: nom et prénom de l'acteur, film dans lequel il joue, date du film, rôle dans le film, réalisateur du film.

La liste sera triée en ordre croissant des noms des acteurs et pour un même acteur en ordre décroissant des titres de film.

Vous créerez enfin un fichier csv contenant le résultat.

Solution
import csv


def de_csv_vers_dico(fichier):
    """
    fichier -- nom d'un fichier csv (sans l'extension) 

    renvoie la liste de dictionnaires associée au fichier.
    """
    with open(fichier + '.csv', newline='') as fichiercsv:
        lecture = csv.DictReader(fichiercsv, delimiter=',')
        return [ligne for ligne in lecture]



def de_dico_vers_csv(liste, nomFichier):
    """
    liste -- liste de dictionnaires
    nomFichier -- nom du fichier créé (sans extension)

    crée le fichier csv contenant les contenus des dictionnaires 
    """
    with open(nomFichier + '.csv', 'w', newline='') as fichiercsv:
        entete = [clef for clef in liste[0].keys()]
        ecriture = csv.DictWriter(fichiercsv, fieldnames=entete)
        ecriture.writeheader()
        for ligne in liste:
            ecriture.writerow(ligne)





personnes = de_csv_vers_dico('personna')
jeux = de_csv_vers_dico('joue')
films = de_csv_vers_dico('film')


liste = []
for acteur in personnes:
    for joue in jeux:
            if joue['id_acteur'] == acteur['id_personne']:
                for film in films:
                    if joue['id_film'] == film['id_film']:
                        dico = {'nom': acteur['nom'],
                                'prenom': acteur['prenom'],
                                'film': film['titre'],
                                'annee': film['annee'],
                                'rôle': joue['role']
                        }

                        for realisateur in personnes:
                            if film['id_realisateur'] == realisateur['id_personne']:
                                dico['réalisateur'] =  realisateur['nom']+' '+realisateur['prenom']

                        liste.append(dico)

# on trie:
liste.sort(key= lambda x:x['film'].lower(), reverse= True)
liste.sort(key= lambda x:x['nom'].lower())


de_dico_vers_csv(liste, 'rolesActeurs')

Fichier csv obtenu.