# Les bases de données/Les liens entre tables

Maintenant que l'on sait stocker des données dans une base de données, il nous reste à stocker les liens entre ces informations. Prenons l'exemple d'une entreprise qui veut mémoriser la liste des commandes qu'elle doit honorer à ses clients. Chaque commande a été passée par un client en particulier, ce qui fait que l'on doit ajouter une table pour mémoriser les clients, en plus de la table pour les commandes. Mais comment savoir quel client a passé telle ou telle commande ? De manière plus générale, comment gérer les cas où une ligne/entité dans une table fait référence à des informations situées dans une autre table ?

## Clés étrangères

Les bases de données actuelles, appelées bases relationnelles, utilisent un stratagème assez intéressant pour gérer ces liens entre enregistrements. Ces liens ne sont pas mémorisés dans la base de donnée, mais sont déduit des informations contenues dans les enregistrements, en faisant un bon usage des clés primaires. Un enregistrement A peut faire référence à un enregistrement B en contenant la clé primaire de B. La copie de la clé primaire de B, contenu dans l'enregistrement A est appelée une clé étrangère. La table qui contient l'enregistrement A est appelée la table enfant, tandis que la table qui contient l’enregistrement B auquel il est fait référence est appelée la table parente. On parle de clé étrangère pour dire que la clé est étrangère à la table enfant, et qu'elle fait référence à un enregistrement dans la table parente.
L'utilisation de clés étrangère pose toutefois un problème quand on peut supprimer ou ajouter des enregistrements dans une table : comment garantir que les clés étrangères feront bien référence à un enregistrement valide ? Imaginez que l'enregistrement auquel il est fait référence soit supprimé : la référence sera invalide. Garantir que toute référence vers une table parente soit valide est une contrainte qui porte un nom : on parle d'intégrité référentielle. Pour éviter que cette contrainte soit violée, le SGBD utilise divers mécanismes de propagation de contraintes, qui définissent ce que l'on doit faire dans une table enfant lors de la suppression d'un enregistrement dans une table parent. On peut choisir comment le SGBD doit se comporter lors d'une telle suppression : suivant la table, on peut lui indiquer quoi faire.
| Comportement | Action |
| CASCADE | La première méthode consiste à supprimer tous les enregistrements qui contiennent la clé étrangère, tous les enregistrements qui font référence à celui supprimé. Ainsi, quand on supprime un enregistrement dans une table, tous les enregistrements dans les autres tables qui y font référence sont supprimés : la suppression est propagée dans les tables enfant. |
| SET NULL et SET DEFAULT | Une autre possibilité est de ne pas supprimer les enregistrements enfants, mais de modifier leur clé étrangère. Dans le cas le plus simple, ses attributs sont mis à NULL : c'est le comportement nommé SET NULL. Dans d'autres cas, on peut demander à ce que la clé étrangère soit mise à une valeur par défaut, pas forcément nulle : c'est le comportement SET DEFAULT. |
| RESTRICT | Une dernière méthode de propagation consiste à interdire la suppression d'un enregistrement si celui-ci est référencé dans une autre table. |

## Types de liens

Dans les grandes lignes, on peut classer les liens entre deux tables en trois catégories :
* les correspondances un à un ;
* les correspondances un à plusieurs ;
* les correspondances plusieurs à plusieurs.

### Correspondances un à un

Dans le premier cas, chaque enregistrement de la table enfant fait référence à un seul enregistrement dans la table parent, et réciproquement. Pour donner un exemple, nous allons prendre une table "pays" et une table "capitale" : chaque pays n'a qu'une seule capitale, et une ville n'est capitale que d'un seul pays.
Pour enregistrer ces relations entre tables, il suffit de placer la clé étrangère dans la table appropriée. Dans ce cas, on sélectionne une des deux tables (on peut choisir celle qu'on veut) et celle-ci contiendra les clé étrangère qui pointeront vers l'autre table.

### Correspondances un à plusieurs

Le second cas correspond à la situation où :
* plusieurs lignes dans une table enfant font référence à un unique enregistrement dans une autre table ;
* mais où la réciproque n'est pas vraie : les lignes de l'autre table font systématiquement référence à une seule entité dans la première table.
Pour donner un exemple, nous allons prendre les deux tables nommée "mère" et "enfant" : une mère peut avoir plusieurs enfants, mais la réciproque n'est pas vraie (un enfant n'a qu'une seule mère). Comme autre exemple, on peut donner la relation entre les deux tables "classe" et "élève" : une classe contient plusieurs élèves, mais tout élève n'est que dans une seule classe bien précise.
Pour enregistrer ces relations entre tables, il suffit de placer la clé étrangère dans la table appropriée. Reste que cette fois-ci, on ne peut pas choisir la table qui contiendra la clé étrangère : ce sera obligatoirement une des deux tables, et jamais l'autre. Plus précisément, si on a :
* deux tables nommées A et B ;
* chaque ligne de A pointe vers plusieurs lignes de B ;
* chaque ligne de B pointe vers une seule ligne de A.
Dans ce cas, on doit ajouter une colonne dans la table B pour accueillir les clés étrangères.
Par exemple, reprenons l'exemple avec les deux tables "mère" et "enfant" : il faudra placer une colonne pour les clés étrangères dans la table "enfant". Supposons que l'on ne fasse pas comme cela : il faudra rajouter plusieurs colonnes dans la table "mère" : une pour chaque enfant potentiel. On voit bien que l'on devra ajouter beaucoup plus de colonnes. Et c'est sans compter le cas où le nombre de colonnes à ajouter n'est pas borné : combien de colonnes devrait-t-on ajouter pour l'exemple avec les tables "mère" et "enfant" ? Se limiter à 3 ou 4 ne permettrait pas à la base de fonctionner avec ces familles nombreuses de 5, voire 10/15 enfants.

### Correspondances plusieurs à plusieurs

Enfin, dans le dernier cas, chaque enregistrement dans une table peut pointer vers plusieurs enregistrements dans l'autre table, et cela vaut pour les deux tables. Un exemple est la relation entre une table "livre" et une table "auteur" : un auteur peut avoir écrit plusieurs livres, de même qu'un livre peut avoir été rédigé par plusieurs auteurs. Dans ce cas, les clés étrangères ne sont pas mémorisées dans une des deux tables. Elles sont mémorisées dans une table à part, qui mémorise les liens entre les deux tables. Pour chaque référence <enregistrement de la première table <-> enregistrement dans la seconde table>, cette table mémorise le couple <clés primaire de la première table - clé primaire de la seconde table>.