Nous allons maintenant voir une autre raison à l'existence de la clé primaire.
En plus d'un jeu et de la console qui faisait tourner ce jeu, on rajoute maintenant sur chaque ligne des informations sur la console elle-même (visualisables en rouge ci-dessous) : la date de sortie de la console, sa mémoire et la puissance du microprocesseur.
On voit que les jeux 10 et 11 tournaient sur la même console. Les mêmes informations sont donc présentes plusieurs fois. Ce n'est pas être optimum.
Pour limiter ce problème, la solution envisagée par les bases de données relationnelles est de créer deux relations (jeu et console) contenant au total les mêmes informations qu'avant et de relier ces 2 relations entre elles.
Chaque table a sa propre clé primaire (voir les colonnes rouges) qu'on décide de nommmer id dans les deux cas.
Nouveauté : c'est la colonne bleue de la relation jeu qui permet de relier les deux relations.
L'attribut id_support est une clé étrangère. Chaque valeur de clé étrangère doit être :
soit une valeur valide de clé primaire de la table console;
soit NULL.
Regardons maintenant comment utiliser cela :
01-A° Quatre choses :
Localiser le p-uplet de la relation jeu dont la clé primaire id vaut 10.
Quelle est la valeur de la clé étrangère id_support pour ce p-uplet ?
Que peut-on en tirer comme informations sur la console de ce jeu ?
On présente ci-dessous le p-uplet virtuel obtenu en concaténant les attributs de la relation jeu et les attributs de la relation console . Dans l'en-tête, une formule expliquant comment on a fait la liaison entre les deux relations. Question : Comment pourrait-on décrire cette équation en français : mêmes valeurs de clés primaires ? mêmes valeurs de clés étrangères ? Une clé étrangère valant une clé primaire ?
id
jeu
description
sortie
editeur
fichier_image
genre
jeu_retro.id_support = console.id
nom
RAM
date_sortie
10
PITFALL!
Pitfall Harry, un explorateur, ramasse des objets éparpillés dans la jungle.
1983
Activision
Plate-formes
3
C64
64 ko
1982-08-01
...CORRECTION...
Localiser le p-uplet de la relation jeu_retro dont la clé primaire vaut 10.
Il s'agit de l'avant dernière ligne, le PITFALL ! sorti en 1983.
Quelle est la valeur du champ id_support de ce p-uplet ?
On lit 3 dans le champ de l'atttribut id_support.
Que peut-on en tirer comme informations sur la console de ce jeu ?
En allant voir dans la relation console, on peut voir qu'il s'agit d'une version du jeu pour le C64, ordinateur personnel sorti en 1982 et disposant de 64 ko de mémoire.
Comment pourrait-on décrire cette équation en français : mêmes valeurs de clés primaires ? mêmes valeurs de clés étrangères ? Une clé étrangère valant une clé primaire ?
On voit bien qu'on a une égalité entre une clé étrangère et une clé primaire.
01-B° L'avantage de réaliser cette jointure en place mémoire est évident si le nombre de jeux est bien plus grand que le nombre de consoles : nous n'aurions pas à recopier en mémoire de multiples fois les mêmes informations, il suffit de suivre la liaison entre clé étrangère vers clé primaire. Quel risque cela annule-t-il ?
...CORRECTION...
Il n'existe plus qu'une unique source d'information pour chaque colonne. Cela évite les erreurs bêtes comme le fait qu'on indique une fois que sa RAM est de 64 ko et ailleurs 67 ko à cause d'une erreur de frappe.
1.1 Contrainte de REFERENCE (liée à la valeur de la clé étrangère, foreign key)
A - Liaison entre relations
Le système de liaison entre les relations est donc basé sur :
des attributs nommés clés primaires respectant la contrainte d'UNICITE : (UNIQUE et NOT NULL) en SQL, elles identifient un n-uplet avec certitude.
des attributs nommés clés étrangères dont la valeur permet de faire la liaison vers un autre n-uplet dont on connait la valeur de clé primaire.
B - Contrainte de REFERENCE
La contrainte de REFERENCE impose que la valeur d'une clé étrangère :
soit NULL si on ne connait pas l'information;
soit correspond à une valeur de clé primaire d'un autre enregistrement.
C - Conventions
On identifie les clés étrangères :
en plaçant un caractère dièse# devant leur nom dans un schéma relationnel
parfois en plaçant le nom de la table visée en suffixe : id_console
Exemple
Dans l'exemple des consoles et des jeux retro, la clé étrangère id_support doit être affectée à NULL, 1, 2 ou 3.
02-A° On fournit ci-dessous les schémas relationnels des relations jeu et console.
Pour distinguer les attributs des deux relations, on utilise souvent la notation pointée de la POO relation.attribut.
Par exemple : jeu.id désigne un attribut id présent dans la relation jeu.
Question : Donner les noms des clés présentes dans les deux tables. Pour chacune, préciser son type primaire ou étrangère en justifiant votre choix.
...CORRECTION...
jeu.id désigne une clé PRIMAIRE car l'attribut est souligné.
jeu.id_support désigne une clé ETRANGERE car l'attribut est précédé d'un #.
console.id désigne une clé PRIMAIRE car l'attribut est souligné.
02-B° Les valeurs de l'attribut id de la relation jeu (la première "colonne" à gauche) doivent-elles être toutes différentes ? Quelle contrainte doit respecter cet attribut ?
...CORRECTION...
Oui : nous avions vu qu'il s'agit de la clé primaire de la relation.
Elle doit respecter la contrainte d'intégrité d'UNICITE (UNIQUE et NOT NULL).
02-C° Les valeurs de l'attribut id_support de la relation jeu (la dernière "colonne" de la table) doivent-elles être toutes différentes ? Quelle contrainte doit respecter cet attribut ?
...CORRECTION...
Non, on peut avoir plusieurs fois la même valeur : id_support est une clé étrangère, plusieurs jeux peuvent mener à la même console.
La contrainte d'intégrité de REFERENCE impose par contre que toutes les valeurs correspondent à une vraie valeur de clé primaire présente dans l'autre table, ou soit NULL.
Nous avons deux tables mais nous voudrions créer un affichage ressemblant à ceci pour notre site Web parlant de jeux vidéo retro de types plateformes : on veut filter uniquement les jeux de plateformes mais obtenir un seul "tableau".
Le principe : faire une jointure.
Qu'est-ce que cela veut dire ?
1.2 Mécanisme de la jointure (interne)
Principe du JOIN, nommé aussi INNER JOIN
On veut projeter tous les attributs des deux relations en utilisant ce mécanisme :
Pour chaque n-uplet de jeu dont la clé étrangère n'est pas NULL :
Localise le n-uplet de console qui a la bonne valeur de clé primaire.
Concatène les deux p-uplets pour former un nouveau p-uplet.
Ajoute cette concaténation à la projection
Exemple
On obtient alors ceci :
id
jeu
description
sortie
editeur
genre
fichier_image
id_support
id
nom
RAM
date_sortie
7
Flight Simulator
Simulation de piotage d'avion avec des pixels gros comme des camions !
1980
subLOGIC
Simulateur
1
1
Apple II
4 ko
1977-06-10
9
PITFALL!
Pitfall Harry, un explorateur, ramasse des objets éparpillés dans la jungle.
1982
Activision
Plate-formes
2
2
Atari 2600
4 ko
1977-10-14
10
PITFALL!
Pitfall Harry, un explorateur, ramasse des objets éparpillés dans la jungle.
1983
Activision
Plate-formes
3
3
C64
64 ko
1982-08-01
11
Boulder Dash
Rockford, mineur téméraire, ramasse des diamants et tente de ne pas se faire écraser par les énormes pierres instables.
1983
First Star Software
Plate-formes
3
3
C64
64 ko
1982-08-01
n-uplets manquants
Notez que dans une jointure interne, on décide de ne jamais inclure les n-uplets de jeu dont la clé étrangère est NULL (les jeux sans console) ou les n-uplets de console jamais référencés par une clé étrangère (les consoles qui n'ont pas de jeux !).
Une jointure interne ne construit donc que les concaténations où il existe bien une liaison entre un jeu et une console.
On perd donc ici Donkey Kong car sa clé étrangère vaut NULL.
Par contre, chaque console est bien présente car toutes possèdent au moins un jeu.
On fournit, cette fois, le schéma de la base sous forme de graphique. Les clés primaires sont soulignées, les clés étrangères préfixées par # (qui n'est pas dans son nom, c'est juste un indice visuel) et les liaisons entre clés étrangères et primaires représentées par une flèche.
Remarquez bien que ce schéma comporte donc le schéma relationnel de chacune des tables ainsi que d'indications sur la manière d'utiliser les clés.
04° Un élève fournit ce schéma relationnel de la relation job (sous forme abstraite). Cette représentation est incomplète. Que manque-t-il pour avoir tous les points ?
07° Quelle requête doit-on faire pour obtenir la même chose mais uniquement avec les films de 2016 et plus ? Trier le résultat par année de sortie, du plus récent au plus ancien. On rajoutera l'année dans la réponse de façon à vérifier que la requête fonctionne bien.
Nous allons maintenant faire le lien entre la relation job et la relation person.
08° Projeter la clé primaire id et le nom de la personne occupant un emploi ainsi que le type de poste (category) qu'elle occupe pour chaque emploi qu'on peut trouver dans la base de données.
On remarquera que la table job est particulière puisqu'elle contient deux clés étrangères. Elle joue un rôle central dans les jointures entre les titres et les personnes qui y ont participé : title - job - person.
En réalité, on peut utiliser plusieurs JOIN ...ON ... = ... dans une requête. Nous allons donc pouvoir faire la liaison entre un titre et les gens qui ont travaillé sur ce projet.
09° Expliquer clairement ce que fait cette requête, ligne par ligne.
12° Comptabiliser le nombre de films de 180 minutes et plus pour lesquels on dispose d'employés : il suffit de chercher les valeurs DISTINCTES au niveau du titre de l'un des attributs de cette jointure titre-emploi et de les compter.
14° Obtenir la liste des films dans lesquels Bruce Willis a participé en tant qu'acteur. On affichera également les rôles qu'il incarne dans ces films.