3. Relations entre éléments

3.1. Cardinalité d'une relation

La cardinalité d'une relation nous donne la façon dont les éléments d'une table sont en relation avec les éléments d'une autre table. Il y a quatre cardinalités possibles :
  • cardinalité 1:1 : chaque élément de la première table est en relation avec un unique élément de la seconde table. La réciproque est vraie : chaque élément de la seconde table n'a qu'un seul élément de la première table comme antécédent.
  • cardinalité 1:p : chaque élément de la première table peut avoir plusieurs éléments de la seconde table en relation. En revanche, les éléments de la seconde table ne peuvent avoir qu'un seul antécédent.
  • cardinalité p:1 : chaque élément de la première table ne peut avoir qu'un unique élément de la deuxième table en relation. En revanche, un élément de la seconde table peut avoir plusieurs éléments de la première comme antécédent.
  • cardinalité n:p : chaque élément de la première table peut avoir plusieurs éléments de la seconde en relation, et les éléments de la seconde table peuvent aussi avoir plusieurs antécédents.
À chacun de ces types de relation correspondent une façon de construire une structure de table, et une structure de clés primaires / clés étrangères.

3.2. Relation 1:1

Une relation 1:1 existe par exemple entre une commune et un maire : une commune ne peut avoir qu'un seul maire, et on ne peut pas être maire de plusieurs communes. Établissons la structure de tables qui permet de stocker cette relation.

Exemple 61. Relation 1:1

-- table des communes
 create  table Communes (
   id  int  primary  key,
   nom_commune  varchar(32),
   id_maire  int
) ;

 -- table des maires
 create  table Maires (
   id  int  primary  key, 
   nom_maire  varchar(32)
) ;

 -- id_maire doit référencer un maire
 alter  table Communes
 add  constraint FK_communes_maires 
    foreign  key CommunesBis(id_maire) 
    references Maires(id) ;

 -- requête permettant de dresser la liste des communes avec leur maire
 select nom_commune, nom_maire
 from Communes
    join Maires  on Communes.id = Maires.id ;

Ici, nous avons décidé arbitrairement que la table qui porte l'information de jointure est la table Communes. Cela aurait très bien pu être l'inverse. Nous avons déjà écrit une telle jointure lorsque nous avons construit la liste des marins et leurs communes de naissance. Nous verrons plus en détails l'utilisation de join.

3.3. Relation 1:p

Nous avons déjà vu une relation de ce type dans nos exemples : il s'agit de celle qui lie un joueur à son équipe. Un même joueur n'appartient qu'à une seule équipe, mais une équipe est composée de plusieurs joueurs. Voyons comment on peut écrire une telle relation.

Exemple 62. Relation 1:p

-- création de la table des joueurs
 create  table Joueurs (
    id  int  primary  key, 
    nom_joueur  varchar(32), 
    id_equipe  int
) ;

 -- création de la table des équipes
 create  table Equipes (
    id  int  primary  key, 
    nom_equipe  varchar(32)
) ;

 -- id_equipe doit référencer l'id d'une équipe
 alter  table Joueurs
 add  constraint FK_joueur_equipe 
     foreign  key Joueurs(id_equipe)  references Equipes(id) ;

 -- requête permettant de dresser la liste des joueurs des équipes
 select nom_equipe, nom_joueur
 from Joueurs
     join Equipes  on Joueurs.id_equipe = Equipes.id
 order  by nom_equipe, nom_joueur ;

Cette fois-ci, la table Equipes ne peut pas référencer directement des id de joueurs, du fait que la relation est multiple. C'est donc la table Joueurs qui doit porter l'information de jointure. On notera que la requête de sélection s'écrit de la même façon que dans le cas d'une relation 1:1.

3.4. Relation p:1

Une relation p:1, dans le modèle relationnel, est le symétrique d'une relation 1:p. Dans le contexte du mapping objet / relationnel, les choses sont un peu différentes. On peut prendre un autre exemple : la relation qui existe entre les communes de naissance des marins, et les marins. Une même commune voit naître plusieurs marins.

Exemple 63. Relation p:1

-- création de la table des communes
 create  table Communes (
    id  int  primary  key, 
    nom_commune  varchar(32)
) ;

 -- création de la table des marins
 create  table Marins (
    id  int  primary  key, 
    nom_marin  varchar(32),
    id_commune  int
) ;

 -- une commune de naissance doit être référencée par un marin
 alter  table Marins
 add  constraint FK_marins_communes
     foreign  key Marins(id_commune)  references Communes(id) ;
    
 -- construction de la table des communes et des marins
 select nom_commune, nom_marin 
 from Communes
     join Marins  on Communes.id = Marins.id_commune ;

Encore une fois, la relation de sélection s'écrit de la même manière que dans le cas d'une relation 1:1.

3.5. Relation n:p

Les trois premiers cas que nous avons vus se ressemblent tous. Le cas de la relation n:p est en revanche un peu plus ardu. Comme nous l'avons vu dans les cas 1:p et p:1, la table qui se trouve du côté multiple de la relation ne peut pas porter l'information de jointure. Comme dans le cas n:p, les deux tables portent une relation multiple, aucune d'entre elles ne peut porter cette information. On résoud ce problème en créant une table technique, intermédiaire, appelée table de jointure . Dans le cas de la relation entre nos musiciens et leurs instruments (un musicien peut jouer de plusieurs instruments, et un même instrument peut être pratiqué par plusieurs musiciens), cette table sera elle-même en relation 1:p avec chacune des tables musiciens et instruments. Écrivons ceci sur un exemple.

Exemple 64. Relation n:p

-- création de la table des musiciens
 create  table Musiciens (
    id  int  primary  key, 
    nom_musicien  varchar(32)
) ;

 -- création de la table des instruments
 create  table Instruments (
    id  int  primary  key, 
    nom_instrument  varchar(32)
) ;

 -- création de la table de jointure
 create  table Musiciens_Instruments (
    id_musicien  int  not  null, 
    id_instrument  int  not  null, 
     primary  key(id_musicien, id_instrument)
) ;

 -- la table de jointure doit référencer un musicien
 alter  table Musiciens_Instruments
 add  constraint FK_musiciens_instruments
     foreign  key Musiciens_Instruments(id_musicien)  references Musiciens(id) ;

 -- la table de jointure doit référencer un instrument
 alter  table Musiciens_Instruments
 add  constraint FK_instruments_musiciens
     foreign  key Musiciens_Instruments(id_instrument)  references Instruments(id) ;

 -- la requête permettant d'afficher les musiciens et leurs instruments
 select nom_musicien, nom_instrument
 from ((Musiciens
        join Musiciens_Instruments  on Musiciens.id = Musiciens_Instruments.id_musicien) 
       join Instruments  on Instruments.id = Musiciens_Instruments.id_instrument) ;

Cette technique d'ajout de table de jointure est très utilisée dans la pratique. On notera la double jointure dans la requête select, et le placement des parenthèses.
Introduction à SQL
Retour au blog Java le soir
Cours & Tutoriaux
Table des matières
Introduction
1. Un peu d'histoire
2. Organisation de la présentation
Un premier exemple
1. Un premier exemple
1.1. Construction d'une première table
1.2. Enregistrer quelques données
1.3. Extraire des données
2. Trier, classer, calculer
2.1. Classer des données
2.2. Trier des données
2.3. Effectuer des calculs
2.4. Mise à jour d'une valeur
3. Sélection sur plusieurs tables
3.1. Ajout du lieu de naissance
3.2. Clés primaires et clés étrangères
Organisation des données
1. Introduction
2. Bases de données, schémas et tables
2.1. Création d'une table
2.2. Création d'une colonne
2.3. Contraintes sur une table
2.4. Nommage des contraintes
2.5. Exemples de création de tables
2.6. Modification d'une table
2.7. Effacement d'une table
2.8. Remarques sur restrict et cascade
3. Types de données
3.1. Les types numériques
3.2. Les types caractère
3.3. Les types temporels
3.4. Les types binaires
3.5. Type auto-incrémental de MySQL
3.6. Type auto-généré de Derby
3.7. Séquences d'Oracle
Manipulation des données
1. Introduction
2. Extraire des données : select
2.1. Extraire des données d'une table unique
2.2. Clause where
2.3. Requêtes imbriquées
2.4. Fonctions d'agrégation, groupage
3. Supprimer des données : delete
3.1. Forme générale du delete
3.2. Effacement en cascade
3.3. Fonctionnement du delete
4. Ajouter des données : insert
4.1. Forme générale de l' insert
4.2. Copie d'une table dans une autre
5. Mettre à jour des données : update
5.1. Forme générale de l' update
5.2. Mise à jour avec une requête imbriquée
Interrogations sur plusieurs tables
1. Introduction
2. Formes normales
2.1. Première forme normale
2.2. Deuxième forme normale
2.3. Troisième forme normale
2.4. Formes normales d'ordres supérieurs
3. Relations entre éléments
3.1. Cardinalité d'une relation
3.2. Relation 1:1
3.3. Relation 1:p
3.4. Relation p:1
3.5. Relation n:p
4. Jointures
4.1. Jointure interne
4.2. Jointure externe
4.3. Auto-jointure
5. Unions
6. Vues
6.1. Création d'une vue
6.2. Exemples de vues
Transactions
1. Introduction
2. Isolation des transactions
2.1. ACIDité d'une transaction
2.2. Définition de l'isolation
3. Gestion d'une transaction
3.1. Mode auto-commit
3.2. Fixer le niveau d'isolation
3.3. Démarrer une transaction
3.4. Terminer une transaction
3.5. Remarques importantes
Index
1. Introduction
2. Manipulation d'index
2.1. Création automatique d'index
2.2. Création manuelle d'index