Aller au contenu

Clés étrangères et relations

Stocker des informations

Imaginons maintenant que l'on souhaite stocker des informations sur quel étudiant suit quel cours. On pourrait faire quelque chose qui ressemble à ceci :

Nom Code Session Sigle cours Duree cours Nom enseignant Code employe
Tony Stark 1234567 H22 420-2B4-VI 60 Kara Danvers 7654
Natasha Romanov 3456789 H22 420-2B4-VI 60 Kara Danvers 7654
Tony Stark 1234567 H22 420-2A6-VI 90 Bruce Wayne 8765
Thor Odison 6789012 H22 420-2A6-VI 90 Bruce Wayne 8765

Problèmes ?

  • Répétition des valeurs = perte d'espace mémoire !
  • Difficile de faire des modifications (ex. : changer le nom de l'enseignant)

Relations entre tables

Il faut découper nos informations entre plusieurs tables et faire des références entre les tables. On référence alors la clé primaire d'une des tables dans l'autre table.

C'est ce que l'on appelle une clé étrangère (FOREIGN KEY).

On remarque la direction de la flèche, de la table appelée « enfant » vers la table « parent ».

On ajoute dans la table enfant un champ enseignant et une annotation de clé étrangère. Donc ici chaque cours possède un enseignant.

erDiagram  
    enseignants ||--o{ cours : "enseigne" 
enseignants {
        NUMERIC(8) code_employe
        VARCHAR(255) nom
        VARCHAR(255) prenom
        NUMERIC(9) num_assurance_sociale
        TINYINT anciennete
    }
cours {
        INTEGER cours_id PK
        NUMERIC(8) enseignant FK
        CHAR(11) sigle
        TINYINT duree "=60"
        VARCHAR(255) nom
    }    

Importances des relations

On trouve rarement une table isolée dans un modèle de base de données (table en relation avec aucune autre table).

Pour faire une analogie, on pourrait comporarer une table isolée à du code qui n'est pas référencé (fonction qui n'est jamais appelée) dans le domaine de la programmation.

Clé étrangère SQL

Pour indiquer une clé étrangère, on ajoute la contrainte suivante dans la requête de création de la table.

FOREIGN KEY (nom_colonne) REFERENCES table_parent(cle_primaire)

Exemple avec la table cours

CREATE TABLE cours (  
    id INTEGER PRIMARY KEY AUTO_INCREMENT,  
    sigle CHAR (11),  
    duree TINYINT, 
    nom VARCHAR(255),
    enseignant NUMERIC(8),
    FOREIGN KEY (enseignant) REFERENCES enseignants (code_employe));

Ici rien ne change dans la création de la table enseignants (la table ne sait pas qu'elle est utilisée comme clé étrangère ailleurs).

Suppression de tables qui contiennent des relations

erDiagram  
    enseignants ||--o{ cours : "enseigne" 
enseignants {
        NUMERIC(8) code_employe
        VARCHAR(255) nom
        VARCHAR(255) prenom
        NUMERIC(9) num_assurance_sociale
        TINYINT anciennete
    }
cours {
        INTEGER cours_id PK
        NUMERIC(8) enseignant FK
        CHAR(11) sigle
        TINYINT duree "=60"
        VARCHAR(255) nom
    } 

Peut-on supprimer la table enseignants sans supprimer la table cours? Pourquoi?

Attention

Pour pouvoir supprimer une table, celle-ci ne doit pas être référencée par une autre table. Autrement dit, il faut que sa clé primaire ne soit pas une clé étrangère pour une ou plusieurs autres tables.

Si l'on pouvait faire la suppression, la table cours aurait une colonne qui contiendrait des clés d'une table inexistante.

Ordre de création

Afin d'ajouter les contraintes de clés étrangères, la table parent doit être créée avant la table enfants.

Autrement, vous aurez une erreur SQL disant que votre contrainte FOREIGN KEY référence une table inexistante.

--- Exercice 1.5.1 ---

Proposez un modèle de base de données illustrant qu'un enseignant est responsable d'un programme.

Implémentez la base de données correspondant à votre modèle.

Tables d'association

Les clés étrangères permettent de référer un enregistrement dans une autre table. Qu'arrive-t-il dans la situation suivante:

Une BD permet de gérer les inscriptions des étudiants à leurs cours. Comment représenter le fait qu'un étudiant puisse s'inscrire à plusieurs cours et qu'à un même cours, plusieurs étudiants puissent s'inscrire ?

On ajoute une table dont le rôle dont les enregistrements représentent chaque relation.

Par exemple, on ajouterait une table inscriptions pour représenter notre association. Comme inscriptions est créée spécialement pour représenter une association, elle est appelée table d'association.

On voit ici que la table inscriptions assure l'association entre cours et etudiants.

On peut voir que deux tables sont associées si l'on peut suivre avec notre doigt d'une table à l'autre en empruntant les flèches comme des chemins (ici le sens des flèches n'a pas d'importance).

erDiagram  
    etudiants ||--o{ inscriptions : " " 
etudiants {
        NUMERIC(8) code PK
        VARCHAR(255) nom
        YEAR annee_admission
        DATETIME date_naissance
        VARCHAR(10) programme
     }
    inscriptions }o--|| cours : " "
inscriptions {
        INTEGER cours PK
        INTEGER etudiant PK
        CHAR(3) session
    }
cours {
        INTEGER cours_id PK
        NUMERIC(8) enseignant FK
        CHAR(11) sigle
        TINYINT duree "=60"
        VARCHAR(255) nom
    }    

Mais... un instant!

Dans la table inscriptions la clé primaire est-elle vraiment composée de deux colonnes?

Oui, c'est possible: c'est appelé une clé composée.

erDiagram   
    etudiants ||--o{ inscriptions : " " 
etudiants {
        NUMERIC(8) code PK
        VARCHAR(255) nom
        YEAR annee_admission
        DATETIME date_naissance
        VARCHAR(10) programme
     }
    inscriptions }o--|| cours : " "
inscriptions {
        INTEGER cours PK
        INTEGER etudiant PK
        CHAR(3) session
    }
cours {
        INTEGER cours_id PK
        NUMERIC(8) enseignant FK
        CHAR(11) sigle
        TINYINT duree "=60"
        VARCHAR(255) nom
    }   

Clé composée

Pour indiquer une clé composée dans une base de données, nous devrons utiliser la notation de contrainte.

Après avoir déclaré les colonnes, on indique

PRIMARY KEY (nom_colonne1, nom_colonne2,  )

Ne fonctionne pas :

CREATE TABLE inscriptions(
    etudiant NUMERIC(7) PRIMARY KEY, 
    cours INTEGER PRIMARY KEY,
    FOREIGN KEY (etudiant) REFERENCES etudiants (code),
    FOREIGN KEY (cours) REFERENCES cours (cours_id));

Bonne écriture :

CREATE TABLE inscriptions(
    etudiant NUMERIC(7), 
    cours INTEGER,
    PRIMARY KEY (etudiant, cours),
    FOREIGN KEY (etudiant) REFERENCES etudiants (code),
    FOREIGN KEY (cours) REFERENCES cours (id_cours));

Notation de contraintes

La notation contrainte de PRIMARY KEY s'utilise aussi en présence d'une clé simple (clé comportant une seule colonne).

La notation vue précédemment constitue un raccourci intéressant lorsqu'on travaille.

On revient plus en détail sur les contraintes dans le Chapitre 4 - Assurer l'intégrité des données.