Modèle relationnel ================== <style> .reveal ol, .reveal dl, .reveal ul { display: block; text-align: left; margin: 0 0 0 1em; } table { margin: 1em auto!important; } </style> <img class="centre image-responsive" src="https://upload.wikimedia.org/wikipedia/en/5/58/Edgar_F_Codd.jpg" alt="Edgar Codd"> <p class="legende"> <small> <strong>Edgar F. Codd</strong> <br>Source : <a href="https://upload.wikimedia.org/wikipedia/en/5/58/Edgar_F_Codd.jpg" target="_blank">wikimedia.org</a> </small> </p> <div markdown="1"> <small> *Ce document a été créé en collaboration avec Claude AI (modèle Claude Sonnet 3.5, version du 10/09/2024), qui a été utilisé pour transposer le cours correspondant (accessible [ici](modele-relationnel)) en un diaporama. Spoile : Claude a été plutôt mauvais. Pour voir la conversation [cliquez ici](https://aiarchives.org/id/1NLhr9D6XuPDVRDItR51-p).* </small> </div> --- # Introduction ---- ## Introduction - Traitements informatiques actuels : nécessité de gérer des données de plus en plus nombreuses - Limitations des fichiers CSV pour les gros volumes de données car : * le volume des données est gigantesque * les requêtes peuvent être (très) complexes * les données peuvent être utilisées simultanément par différents programmes et utilisateurs > Comment gérer (mémoriser et traiter) un ensemble volumineux de données ? ---- ## Introduction <!-- <div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;"> <iframe src="https://geo.dailymotion.com/player.html?video=x71hy5c" style="width:100%; height:100%; position:absolute; left:0px; top:0px; overflow:hidden; border:none;" allowfullscreen title="Dailymotion Video Player" allow="web-share"> </iframe> </div> --> ---- ## Introduction - **Solution** : utilisation de **bases de données *relationnelles*** - SGBD (Système de Gestion de Base de Données) = logiciel pour interagir avec une base de données (nécessaire) --- # Modèle relationnel ---- ## Modèle relationnel <img class="r-stretch centre image-responsive" src="https://upload.wikimedia.org/wikipedia/en/5/58/Edgar_F_Codd.jpg" alt="Edgar Codd"> <p class="legende"> <small> <strong>Edgar F. Codd</strong> <br>Source : <a href="https://upload.wikimedia.org/wikipedia/en/5/58/Edgar_F_Codd.jpg" target="_blank">wikimedia.org</a> </small> </p> - Défini en 1970 par Edgar F. Codd (prix Turing 1981) dans ses travaux chez IBM - Basé sur des concepts mathématiques - Modélise les **relations** entre informations - Indépendant de toute considération informatique ---- ## Relation, attribut, domaine, schéma <img class="centre image-responsive" src="data/vinyl.svg" alt="diagramme" width="200"> **Exemple** : Un disquaire qui permet d'emprunter des albums de musique. * L'ensemble de ses albums peut être représenté par l'ensemble : ``` Album = { ("I Still Do", "Eric Clapton", 2016, Vrai), ("Axis: Bold as Love", "Jimi Hendrix", 1967, Faux), ("Continumm", "John Mayer", 2006, Faux), ... } ``` ---- ### Relation, attribut, domaine, schéma (suite) ``` Album = { ("I Still Do", "Eric Clapton", 2016, Vrai), ("Axis: Bold as Love", "Jimi Hendrix", 1967, Faux), ("Continumm", "John Mayer", 2006, Faux), ... } ``` - Cet ensemble représente une **relation** (la relation *Album*) - Chaque élément (ligne) s'appelle un **enregistrement** - Les composantes de chaque enregistrement sont identiques, on parle des **attributs** de la relation. Ici, il y en 4 : * `titre` : titre de l'album * `artiste` : le ou les artistes de l'album * `annee` : année de parution de l'album * `dispo` : disponibilité de l'album ---- ### Relation, attribut, domaine, schéma (suite) <div style="font-size:0.85em"> ``` Album = { ("I Still Do", "Eric Clapton", 2016, Vrai), ("Axis: Bold as Love", "Jimi Hendrix", 1967, Faux), ("Continuum", "John Mayer", 2006, Faux), ... } ``` </div> * Chaque attribut possède un **domaine** (= son *type*) : INT, BOOL, TEXT, etc. * Une relation est représentée par son **schéma** = description indiquant pour chaque attribut son *nom* et son *domaine* * Exemple : le schéma de la relation *Album* est : ``` Album(titre TEXT, artiste TEXT, annee INT, dispo BOOL) ``` > ⚠️ Cette relation n'est pas satisfaisante, nous allons l'améliorer ---- ## Représentation tabulaire * Une **relation** est aussi souvent représentée par une **table** (on confond souvent les deux termes): * Exemple (avec notre table `Album`, pas encore satisfaisante) : | titre | artiste | annee | dispo | |-------|---------|-------|-------| | I Still Do | Eric Clapton | 2016 | Vrai | | Axis: Bold as Love | Jimi Hendrix | 1967 | Faux | | Continuum | John Mayer | 2006 | Faux | | ... | | | | ---- ## Base de données relationnelle - Base de données relationnelle = un ensemble de relations - **Schéma d'une base de données relationnelle** = ensemble des schémas des relations - Exemple (incomplet et insatisfaisant) : ``` Album(titre TEXT, artiste TEXT, annee INT, dispo BOOL) Client(...) Emprunt(...) ``` --- # Conception d'une base de données ---- ## Conception d'une base de données * Travail pas toujours aisé mais primordial * En général, on procède ainsi : 1. Déterminer les entités à manipuler 2. Modéliser les entités comme des relations (schéma à donner) 3. Définir les contraintes d'intégrité (domaine, relation, référence) = les propriétés logiques vérifiées par les données à chaque instant ---- ### Contrainte de domaine des attributs * Domaine (= type) à définir obligatoirement pour chaque attribut de chaque relation * **Contrainte de relation** : garantit des valeurs conformes au domaine défini * Concrètement : * Le SGBD s'assure à chaque instant que le domaine de chaque attribut est respecté * Si on essaie de saisir une valeur de type FLOAT pour un attribut ayant INT pour domaine : le SGBD refuse et génère une erreur ---- ### Contrainte de domaine des attributs * Définir le domaine d'un attribut = travail assez simple mais il y a des pièges * Exemple : quel domaine pour un attribut correspondant à un code postal ? <div class="fragment" markdown="1"> Une chaîne de caractères (TEXT) </div> ---- ## Clé primaire - **Clé primaire** = attribut ou réunion d'attributs identifiant de manière unique un enregistrement - À définir obligatoirement pour chaque relation ! ---- ### Clé primaire de la relation *Album* - Que choisir pour la relation *Album* ? ... ``` Album(titre TEXT, artiste TEXT, annee INT, dispo BOOL) ``` ... il y a un problème ! ---- ### Clé primaire de la relation *Album* - **Solution** : * créer une clé primaire "artificielle" `id_album` de type INT * chaque album aura un attribut `id_album` différent - Symbolisée par un soulignement dans le schéma <em>Album</em>(<span style="padding-bottom:3px; border-bottom: 1px solid black;"><em>id_album</em></span> INT, <em>titre</em> TEXT, <em>artiste</em> TEXT, <em>annee</em> INT, <em>dispo</em> BOOL) ---- ### Clé primaire de la relation *Album* * Exemple de la table *Album* avec clé primaire | id_album | titre | artiste | annee | dispo | |----------|-------|---------|-------|-------| | 2 | I Still Do | Eric Clapton | 2016 | Vrai | | 5 | Axis: Bold as Love | Jimi Hendrix | 1967 | Faux | | 24 | Continuum | John Mayer | 2006 | Faux | ---- ### Clé primaire de la relation *Client* * Le disquaire récolte les données suivantes sur ses clients : nom, prénom, adresse email * Quels sont les attributs et leurs domaines ? <div class="fragment"> <em>Client</em>(<em>nom</em> TEXT, <em>prenom</em> TEXT, <em>email</em> TEXT) </div> <div class="fragment"> * Quel(s) attribut(s) peuvent jouer le rôle de clé primaire dans cette relation ? </div> <div class="fragment"> <em>Client</em>(<span style="padding-bottom:3px; border-bottom: 1px solid black;"><em>id_client</em></span> INT, <em>nom</em> TEXT, <em>prenom</em> TEXT, <em>email</em> TEXT) </div> ---- ### Clé primaire de la relation *Client* * Table *Client* avec la clé primaire : <div style="height:1rem"></div> | id_client | nom | prenom | email | | --- | --- | --- | --- | | 1 | Dupont | Florine | dupont.florine@domaine.net | | 5 | Pacot | Jean | jpacot@music.com | | 8 | Rouger | Léa | NULL | | 3 | Marchand | Grégoire | greg.marchand49@music.com | ---- ### Contrainte de relation - **Contrainte de relation** : garantit l'*unicité* des enregistrements - Réalisée par la **clé primaire** pour chaque relation - Concrètement : * le SGBD s'assure à chaque instant que deux enregistrements d'une relation ne possèdent pas des valeurs identiques pour les attributs jouant le rôle de clé primaire * génère une erreur sinon ---- ## Clé étrangère - **Clé étrangère** = attribut qui est clé primaire d'une autre relation - Permet de lier les relations entre elles ---- ## Exemple de relation Emprunt * Un emprunt faire référence à un album (de la relation *Album*) et un client (de la relation *Client*), et à une date d'emprunt (ou de retour) * Une proposition de schéma de la relation *Emprunt* : <div style="font-size:0.75em"> ``` Emprunt(id_client INT, nom TEXT, prenom TEXT, email TEXT, id_album INT, titre TEXT, artiste TEXT, annee INT, dispo BOOL, date DATE) ``` </div> > ⚠️ Cette relation n'est pas satisfaisante pour le moment ! <div class="fragment"> * Quelles sont les clés étrangères de cette relation ? </div> <div class="fragment"> `id_client` et `id_album` </div> ---- ## Exemple de relation Emprunt * Cela donnerait une table *Emprunt* du genre : <div style="font-size:1.2rem; break-word:break"> | id_client | nom | prenom | email | id_album | titre | artiste | annee | dispo | date | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | 1 | Dupont | Florine | dupontf@domaine.net | 5 | Axis: Bold as Love | Jimi Hendrix | 1967 | Faux | 10/09/2021 | | 3 | Mira | Grégoire | gmira49@music.com | 8 | Riding With The King | Eric Clapton et B.B. King | 2000 | Faux | 18/08/2021 | | 3 | Mira | Grégoire | gmira49@music.com | 24 | Continumm | John Mayer | 2006 | Faux | 18/08/2021 | | 5 | Pacot | Jean | jpacot@music.com | 25 | Continumm | John Mayer | 2006 | Faux | 12/09/2021 | </div> * Que choisir comme clé primaire ? <div class="fragment"> On peut choisir `id_album` (car un album ne peut pas être emprunté par deux clients en même temps) </div> ---- ### Redondance des données <div style="font-size:1.2rem; break-word:break"> | id_client | nom | prenom | email | id_album | titre | artiste | annee | dispo | date | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | 1 | Dupont | Florine | dupontf@domaine.net | 5 | Axis: Bold as Love | Jimi Hendrix | 1967 | Faux | 10/09/2021 | | 3 | Mira | Grégoire | gmira49@music.com | 8 | Riding With The King | Eric Clapton et B.B. King | 2000 | Faux | 18/08/2021 | | 3 | Mira | Grégoire | gmira49@music.com | 24 | Continumm | John Mayer | 2006 | Faux | 18/08/2021 | | 5 | Pacot | Jean | jpacot@music.com | 25 | Continumm | John Mayer | 2006 | Faux | 12/09/2021 | </div> * Problème actuel : la **redondance des données** * Il faut éviter de dupliquer les informations entre relations * (et éviter que des mêmes informations se retrouvent dans plusieurs enregistrements d'une même relation) ---- ### Redondance des données * **Solution** : on ne conserve que `id_client`, `id_album` et `date` dans la relation *Emprunt* : <em>Emprunt</em>(<em>#id_client</em> INT, <span style="padding-bottom:3px; border-bottom: 1px solid black;"><em>#id_album</em></span> INT, <em>date</em> DATE) | id_client | id_album | date | | --- | --- | --- | | 1 | 5 | 10/09/2021 | | 3 | 8 | 18/08/2021 | | 3 | 24 | 18/08/2021 | | 5 | 25 | 12/09/2021 | * **Moralité** : on utilise les clés étrangères pour lier les tables entre elles ---- ### Redondance des données * **Pourquoi éviter la redondance des données ?** * coût en mémoire supplémentaire si une même information est stockées inutilement dans plusieurs relations * si des corrections doivent être faites (par exemple un changement de nom) : plus simple de les faire à un seul endroit ---- ## Contrainte de référence - **Contrainte de référence** : garantit la cohérence des liens entre relations - Réalisée par les **clés étrangères** ---- ## Contrainte de référence - Concrètement : * une clé étrangère d'une relation doit nécessaire être la clé primaire d'une autre relation * permet de ne pas ajouter de valeurs fictives qui ne correspondent à aucune entité connue de la base de données ---- ## Contrainte de référence - Concrètement (suite): * un enregistrement ne peut être effacé que si sa clé primaire n'est pas associée à des enregistrements liés dans d'autres relations * on ne peut pas supprimer le client "Dupont Florine" de la relation *Client* car il apparaît dans les enregistrements de la relation *Emprunt* <div style="display:flex; gap:3rem; font-size:1.2rem;"> <div> Table *Client* | id_client | nom | prenom | email | | --- | --- | --- | --- | | 1 | Dupont | Florine | dupont.florine@domaine.net | | 5 | Pacot | Jean | jpacot@music.com | | 8 | Rouger | Léa | NULL | | 3 | Marchand | Grégoire | greg.marchand49@music.com | </div> <div> Table *Emprunt* | id_client | id_album | date | | --- | --- | --- | | 1 | 5 | 10/09/2021 | | 3 | 8 | 18/08/2021 | | 3 | 24 | 18/08/2021 | | 5 | 25 | 12/09/2021 | </div> </div> ---- ## Contrainte de référence - Concrètement (suite) : * une clé primaire ne peut pas être modifiée si l'enregistrement en question est associé à des enregistrements liés dans d'autres tables * on ne peut pas modifier la clé primaire `id_client` du client "Dupont Florine" de la relation *Client* car il apparaît dans les enregistrements de la relation *Emprunt* <div style="display:flex; gap:3rem; font-size:1.2rem;"> <div> Table *Client* | id_client | nom | prenom | email | | --- | --- | --- | --- | | 1 | Dupont | Florine | dupont.florine@domaine.net | | 5 | Pacot | Jean | jpacot@music.com | | 8 | Rouger | Léa | NULL | | 3 | Marchand | Grégoire | greg.marchand49@music.com | </div> <div> Table *Emprunt* | id_client | id_album | date | | --- | --- | --- | | 1 | 5 | 10/09/2021 | | 3 | 8 | 18/08/2021 | | 3 | 24 | 18/08/2021 | | 5 | 25 | 12/09/2021 | </div> </div> ---- ## Lien entre albums et artistes <em>Album</em>(<span style="padding-bottom:3px; border-bottom: 1px solid black;"><em>id_album</em></span> INT, <em>titre</em> TEXT, <em>artiste</em> TEXT, <em>annee</em> INT, <em>dispo</em> BOOL) * Le choix d'utiliser une chaîne de caractères pour l'artiste directement dans la table *Album* peut conduire à quelques problèmes : * rien n'empêche d'associer plusieurs fois le même artiste à un album ("Éric Clapton et Éric Clapton") sans que cela génère d'erreur malgré un problème de cohérence * problème possible de redondance des données si un artiste change de nom (il faudrait le modifier sur tous les enregistrements) ---- ### Lien entre albums et artistes * Solution : * Séparer la relation *Album* en trois relations : *Album*, *Artiste* et *Artiste_de* * Utiliser les clés étrangères pour faire les associations entre artistes et albums <em>Album</em>(<span style="padding-bottom:3px; border-bottom: 1px solid black;"><em>id_album</em></span> INT, <em>titre</em> TEXT, <em>annee</em> INT, <em>dispo</em> BOOL) <em>Artiste</em>(<span style="padding-bottom:3px; border-bottom: 1px solid black;"><em>id_artiste</em></span> INT, <em>nom</em> TEXT, <em>prenom</em> TEXT) <em>Artiste_de</em>(<span style="padding-bottom:3px; border-bottom: 1px solid black;"><em>#id_artiste</em></span> INT, <span style="padding-bottom:3px; border-bottom: 1px solid black;"><em>#id_album</em></span> INT) ---- ### Lien entre albums et artistes <em>Artiste_de</em>(<span style="padding-bottom:3px; border-bottom: 1px solid black;"><em>#id_artiste</em></span> INT, <span style="padding-bottom:3px; border-bottom: 1px solid black;"><em>#id_album</em></span> INT) * Dans la relation *Artiste_de* c'est le couple (id_artiste, id_album) qui forme la clé primaire * un même artiste **et** un même album ne peuvent pas se trouver plusieurs fois dans la relation : empêche d'associer deux fois le même artiste à un même album * un même artiste peut être associé à plusieurs albums (car `id_artiste` seul n'est pas clé primaire) ---- ### Lien entre albums et artistes <div style="display:flex; gap:3rem;font-size:1.2rem;"> <div> Relation _Album_ : | id_album | titre | annee | dispo | | --- | --- | --- | --- | | 2 | I Still Do | 2016 | Vrai | | 5 | Axis: Bold as Love | 1967 | Faux | | 24 | Continuum | 2006 | Faux | | 25 | Continuum | 2006 | Faux | | 8 | Riding With The King | 2000 | Faux | | 11 | Don't explain | 2011 | Vrai | </div> <div> Relation _Artiste_ : | id_artiste | nom | prenom | | --- | --- | --- | | 1 | Clapton | Éric | | 3 | Hendrix | Jimi | | 4 | Mayer | John | | 8 | B.B. King | NULL | | 6 | Hart | Beth | | 15 | Bonamassa | Joe | </div> <div> Relation *Artiste_de* : | id_artiste | id_album | | --- | --- | | 1 | 2 | | 1 | 8 | | 8 | 2 | | 4 | 24 | | 4 | 25 | | 3 | 5 | | 6 | 11 | | 15 | 11 | </div> </div> * Chaque chaîne de caractères n'est enregistrée qu'une seule fois * Utiliser des entiers est plus efficace pour les recherches (comparaisons entre entiers plus rapide qu'entre chaînes de caractères) ---- ## Bilan de modélisation de la base de données ### Schéma final <em>Album</em>(<span style="padding-bottom:3px; border-bottom: 1px solid black;"><em>id_album</em></span> INT, <em>titre</em> TEXT, <em>annee</em> INT, <em>dispo</em> BOOL) <em>Artiste</em>(<span style="padding-bottom:3px; border-bottom: 1px solid black;"><em>id_artiste</em></span> INT, <em>nom</em> TEXT, <em>prenom</em> TEXT) <em>Artiste_de</em>(<span style="padding-bottom:3px; border-bottom: 1px solid black;"><em>#id_artiste</em></span> INT, <span style="padding-bottom:3px; border-bottom: 1px solid black;"><em>#id_album</em></span> INT) <em>Client</em>(<span style="padding-bottom:3px; border-bottom: 1px solid black;"><em>id_client</em></span> INT, <em>nom</em> TEXT, <em>prenom</em> TEXT, <em>email</em> TEXT) <em>Emprunt</em>(<em>#id_client</em> INT, <span style="padding-bottom:3px; border-bottom: 1px solid black;"><em>#id_album</em></span> INT, <em>date</em> DATE)</code> ---- ## Bilan de modélisation de la base de données ### Autre représentation : un diagramme <img class="centre image-responsive" src="data/diagramme_bdd.png" alt="diagramme"> --- # Bilan ---- ## Bilan - Modèle relationnel pour structurer les données - Relations avec attributs et domaines - Clés primaires pour définir de manière unique les enregistrements d'une relation - Clés étrangères pour lier les relations - Contraintes d'intégrité à respecter : - de domaine - de relation (réalisée par clé primaire) - de référence (réalisée par clés étrangères) - Conception réfléchie pour éviter les anomalies - Prochaine étape : utilisation du langage SQL pour interagir avec la base de données --- #### Références - Equipe éducative DIU EIL, Université de Nantes. - Cours OpenClassrooms pour l'idée de la base de données d'un disquaire : [Découvrez le framework Django](https://openclassrooms.com/fr/courses/4425076-decouvrez-le-framework-django). - Livre *Numérique et Sciences Informatiques, 24 leçons, Terminale*, T. BALABONSKI, S. CONCHON, J.-C. FILLIATRE, K. NGUYEN, éditions ELLIPSES. - Livre *Prepabac NSI, Tle*, G. Connan, V. Petrov, G. Rozsavolgyi, L. Signac, éditions HATIER. - Cours de Gilles Lassus sur le [modèle relationnel](https://github.com/glassus/terminale_nsi/blob/main/docs/T4_Bases_de_donnees/4.1_Modele_relationnel/cours.md) --- Germain BECKER, Lycée Mounier, ANGERS CC BY-SA ![Licence Creative Commons](https://i.creativecommons.org/l/by-sa/4.0/88x31.png)