Gérer l’historique dans une BDD
Le Royaume d’Althéria et la mission du dev
Imagine. Tu es développeur dans un royaume lointain, Althéria, un pays divisé en plusieurs provinces majestueuses : Solaria, Umbra, Néréïde… Chaque province est dirigée par un souverain. Et comme dans toute bonne histoire, les souverains ne restent pas éternellement sur le trône. Il y a des abdications, des conflits, des retours au pouvoir, parfois même des coups d’État.
Toi, humble artisan du code, on t’a confié une mission cruciale :
Créer une application qui garde une trace fidèle de chaque changement de souverain.
Pas juste savoir qui est roi aujourd’hui, non. On veut toute l’histoire :
- Qui a dirigé quand ?
- Pourquoi ce n’est plus lui ?
- Qui l’a remplacé ?
- Et depuis combien de temps ?
Bref, on veut une mémoire numérique du trône. Pas question de perdre l’info dans les brumes du passé.
Et là, tu te dis : “Bon, je vais faire une table souverain avec un nom et une date… et quand ça change, je fais un UPDATE.”
❌ Mauvaise idée. Tu viens de perdre le passé.
C’est là qu’on entre dans le monde des SCD — Slowly Changing Dimensions — un concept bien connu en business intelligence, mais qu’on va explorer ici à la sauce Althéria. Accroche-toi, c’est simple quand on l’explique bien .
Pour pratiquer ce cours en local tu peux lancer ce petit conteneur et go sur adminer via le port http://localhost:8081/, et puis tu crée une petite bdd.
mkdir altheria
cd altheria
nano docker-compose.yml # et tu copie colle le code ci-dessous
docker compose up -d --build # pour lancer le conteneur
services:
mariadb:
image: mariadb:10.11
container_name: altheria-db
restart: always
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: altheria
MYSQL_USER: althuser
MYSQL_PASSWORD: althpass
ports:
- "3307:3306"
volumes:
- altheria_data:/var/lib/mysql
adminer:
image: adminer
container_name: altheria-adminer
restart: always
ports:
- "8081:8080"
volumes:
altheria_data:
PS: Si docker te fais peur, tu peux utiliser mon guide Docker pour les nuls pour te familiariser avec.
Mais si tu as auparavant un SGBDR (MySQL, MariaDB, etc.) installé dans ta machine, tu peux l'utiliser, et crée une bdd.
SCD ? C’est quoi ce machin-là ?
Bon. Tu as compris l’enjeu : on ne veut pas perdre l’historique. Et dans le monde de la data (surtout en BI ou juste une backend), y’a un concept bien pratique pour ça : les SCD. Ça veut dire Slowly Changing Dimensions, ou en français : dimensions lentement évolutives.
Mais... on n'est pas dans un cours de data warehouse. On est dans Althéria.
Alors imagine que ta base de données, c’est l’archive royale. Et que chaque fois qu’un souverain change, tu dois archiver l’ancien sans l’écraser.
Les SCD, c’est juste des stratégies pour gérer les changements d’informations dans le temps, sans perdre ce qu’il y avait avant.
Et il en existe plusieurs types. On ne va pas tous les faire, mais aujourd’hui on va se concentrer sur deux d’entre eux :
- SCD Type 2 : On garde toutes les versions successives. Chaque changement = une nouvelle ligne.
- SCD Type 4 : On sépare les versions dans une table d’historique, à part.
Ces deux approches vont nous permettre de répondre à des questions comme :
- Qui était souverain en 2010 ?
- Qui a gouverné le plus longtemps ?
- Combien de fois Elric est-il monté sur le trône ?
Et crois-moi, ce n’est pas que de la théorie. Dans le monde réel, on s’en sert pour :
- Suivre l’évolution des postes d’un salarié
- Conserver l’historique des prix dans un catalogue
- Garder trace des adresses passées d’un client
Bref : comprendre d’où viennent les choses, pas juste où elles en sont.
Type 2 : On garde tout, on versionne
On y est. Tu veux garder l’historique dans la même table ? Bienvenue dans le monde du SCD Type 2.
Le principe
À chaque fois qu’un souverain change dans une province, tu n’écrases pas l’ancien.
Tu le désactives (en lui mettant une date_fin, par exemple) et tu ajoutes une nouvelle ligne avec le nouveau souverain et sa date_debut.
Un peu comme si tu collais une nouvelle page dans le grimoire des rois, sans arracher les anciennes.
Structure de la table souverain_type2
CREATE TABLE souverain_type2 (
id INT AUTO_INCREMENT PRIMARY KEY,
nom VARCHAR(100),
province VARCHAR(100),
date_debut DATE,
date_fin DATE,
is_current BOOLEAN DEFAULT true
);
Chaque ligne représente un règne. Le champ is_current permet de savoir si le souverain est toujours en place.
Exemple avec la province de Solaria
-- Elric monte sur le trône
INSERT INTO souverain_type2 (nom, province, date_debut, date_fin, is_current)
VALUES ('Elric', 'Solaria', '2000-01-01', '2010-01-01', false);
-- Lyanna le remplace
INSERT INTO souverain_type2 (nom, province, date_debut, date_fin, is_current)
VALUES ('Lyanna', 'Solaria', '2010-01-01', '2020-06-01', false);
-- Puis Daeron
INSERT INTO souverain_type2 (nom, province, date_debut, date_fin, is_current)
VALUES ('Daeron', 'Solaria', '2020-06-01', '2025-03-01', false);
-- Et Elric revient !
INSERT INTO souverain_type2 (nom, province, date_debut, date_fin, is_current)
VALUES ('Elric', 'Solaria', '2025-03-01', NULL, true);
Avantages
Tu peux faire des requêtes historiques super précises : “Qui était roi de Solaria en 2013 ?” “Combien de fois Elric a régné ?”
Tu n’as aucune perte de données, tout est là, dans la même table.
- ️ Attention Il faut bien gérer les dates de début et fin pour éviter les chevauchements (deux rois actifs en même temps ).
Type 4 : On sépare les archives du présent
Bon, maintenant que tu maîtrises le Type 2, voyons une autre stratégie, un peu plus... organisée. Le Type 4, c’est comme avoir un trône actuel dans une pièce, et les anciens trônes soigneusement rangés dans une salle des archives.
Le principe
Ici, tu as deux tables :
- Une table principale
souverainqui contient uniquement le souverain en cours pour chaque province. - Une table secondaire
historique_souveraindans laquelle tu vas copier l’ancien souverain dès qu’un changement se produit.
Tu n’as jamais plus d’un seul souverain actif dans la table principale, et toutes les histoires passées sont stockées proprement ailleurs.
Structure des tables
-- Table principale (souverain actuel)
CREATE TABLE souverain (
id INT AUTO_INCREMENT PRIMARY KEY,
nom VARCHAR(100),
province VARCHAR(100),
date_debut DATE
);
-- Table d'historique
CREATE TABLE historique_souverain (
id INT AUTO_INCREMENT PRIMARY KEY,
souverain_id INT,
nom VARCHAR(100),
province VARCHAR(100),
date_debut DATE,
date_fin DATE
);
La colonne souverain_id permet de faire le lien entre un enregistrement archivé et le id original dans la table souverain. Mais tu peux aussi fonctionner sans lien si tu préfères une logique plus souple.
Exemple avec Solaria
-- Elric est le souverain actuel
INSERT INTO souverain (nom, province, date_debut)
VALUES ('Elric', 'Solaria', '2025-03-01');
-- Historique : ses règnes précédents et ceux de ses prédécesseurs
INSERT INTO historique_souverain (souverain_id, nom, province, date_debut, date_fin)
VALUES
(1, 'Elric', 'Solaria', '2000-01-01', '2010-01-01'),
(2, 'Lyanna', 'Solaria', '2010-01-01', '2020-06-01'),
(3, 'Daeron', 'Solaria', '2020-06-01', '2025-03-01');
Quand l’utiliser ?
Le Type 4 est super utile si :
Tu veux garder ta table principale ultra simple (juste l’actuel, sans se soucier des dates de fin). Tu n’as besoin de l’historique que dans certains cas précis. Tu veux désactiver un souverain en le déplaçant dans les archives au lieu de le "dater".
Bonus : Tu peux même créer une vue SQL qui reconstitue l’historique complet en combinant les deux tables.
Le Type 4, c’est donc la version “archiviste organisé”. Un peu plus de structure, un peu plus de clarté, surtout si tu travailles avec des systèmes où le "présent" est séparé du "passé" par nature (ex. : gestion RH, catalogues produits...).
Et maintenant que tu as vu les deux approches, on peut passer à la mise en pratique .
Mise en pratique avec Althéria
Les tables sont en place. Maintenant, on joue avec des requêtes concrètes. Voici quelques questions royales... et comment y répondre, selon le type d’historique.
1. Qui est le souverain actuel de Solaria ?
En Type 2
SELECT nom
FROM souverain_type2
WHERE province = 'Solaria' AND is_current = true;
En Type 4
SELECT nom
FROM souverain
WHERE province = 'Solaria';
- Qui régnait sur Solaria en 2013 ?
En Type 2
SELECT nom
FROM souverain_type2
WHERE province = 'Solaria'
AND '2013-01-01' BETWEEN date_debut AND date_fin;
En Type 4
SELECT nom
FROM historique_souverain
WHERE province = 'Solaria'
AND '2013-01-01' BETWEEN date_debut AND date_fin;
- Combien de fois Elric est-il monté sur le trône ? En Type 2
SELECT COUNT(*) AS nb_regnes
FROM souverain_type2
WHERE nom = 'Elric' AND province = 'Solaria';
En Type 4
SELECT COUNT(*) + 1 AS nb_regnes
FROM historique_souverain
WHERE nom = 'Elric' AND province = 'Solaria';
- Quelle a été la durée totale de règne de Lyanna ?
SELECT
SUM(DATEDIFF(date_fin, date_debut)) AS total_jours
FROM souverain_type2
WHERE nom = 'Lyanna' AND province = 'Solaria';
Voilà. Tu as maintenant un mini-parchemin de requêtes royales pour jouer avec ton historique .
Conclusion : Retenir l’histoire, c’est mieux que de l’oublier
Que tu sois en train de construire une base pour un royaume imaginaire ou une vraie appli métier, garder l’historique, c’est souvent plus stratégique qu’on ne le pense.
Les SCD Type 2 et Type 4 sont deux manières simples mais puissantes de préserver les évolutions sans tout écraser. Et avec quelques requêtes bien pensées, tu peux rejouer le passé, comparer, tracer, comprendre.
Mais ce n’est qu’un début...
Tu veux aller explorer d'autres approches ? Regarde du côté des temporal tables).
Bref, l’histoire, c’est chic. Et dans ta base de données, elle mérite sa place.