8.5 KiB
Modélisation d'un système bancaire
Objectifs
- Concevoir un modèle relationnel à partir d’un scénario réaliste.
- Utiliser les contraintes d’intégrité pour garantir la cohérence des données.
- Manipuler des jointures et des relations n–n.
- Comprendre la notion d’héritage logique en base de données.
Contexte
Une banque locale souhaite informatiser la gestion de ses comptes et de leurs titulaires. Chaque compte peut appartenir à une ou plusieurs personnes physiques ou morales.
Vous êtes chargé(e) de concevoir et d’implémenter le schéma relationnel de base permettant de gérer :
- Les clients de la banque, appelés titulaires (holders),
- Les comptes bancaires (accounts),
- Le lien entre les titulaires et les comptes.
1. Les titulaires
Un titulaire (holder) peut être une personne physique (person) ou une entreprise (company).
1.1 Exemple de données
- une personne nommée Françoise Zanetti, née le 12 avril 1995.
- une entreprise nommée Boulangerie de Valorgue, créée le 19/08/2014, numéro d’immatriculation FR19803269968.
1.2 Analyse
- Quelles informations faut-il conserver pour tous les titulaires ?
- Quelles informations sont spécifiques à chaque type de titulaire ?
- Comment représenter cette distinction en base relationnelle ?
Tip
Indice : on peut utiliser une table abstraite
holder, puis des tablespersonetcompanyqui héritent logiquement de celle-ci.
1.3 Contraintes à respecter
- Chaque
personoucompanydoit correspondre à exactement un seulholder. - La suppression d’un
holderdoit supprimer automatiquement la ligne correspondante danspersonoucompany. - Le type doit être contraint à
'PERSON'ou'COMPANY'.
1.4 Vérifications
Lister tous les titulaires.
Supprimer un titulaire, vérifier que cela supprime l'individu ou la société correspondante.
1.5 Réflexion
- Pourquoi séparer
personetcompany? - Pourquoi ne pas tout mettre dans une seule table holder ?
- Quelle contrainte empêche d’insérer une person sans holder ?
1.6 Pour aller plus loin
La banque souhaite désormais que toute personne titulaire d’un compte ait au moins 15 ans à la date de création de sa fiche.
2. Les comptes
- Chaque titulaire peut détenir un ou plusieurs compte.
- Un compte bancaire doit pouvoir appartenir à un ou plusieurs titulaires (compte individuel / compte joint).
- Chaque compte dispose d’un numéro de compte (account number) unique, d’un solde, d'une date d'ouverture et une date de clôture.
- Le solde des comptes ne peuvent être négatifs.
- Dans le cas d'un compte joint, les parts (share) de propriété d'un compte doivent pouvoir être précisées.
2.1 Exemple de données
- Créez un compte individuel pour Françoise Zanetti.
- Ajouter un nouveau titulaire : Justin Hébrard né le 11/03/1993.
- Créez un compte joint pour Françoise et Justin.
3. L'intégrité des données
Lorsque l’on tente d'insèrer une nouvelle personne qui n'a pas l'âge requis. La ligne dans holder est d'abord créée, puis l'insertion dans person échoue à cause de la vérification d'âge. Mais la ligne holder est toujours présente sans être rattachée à une personne.
Chaque commande SQL est exécutée indépendamment. Si la deuxième commande échoue, la première n’est pas annulée automatiquement.
Réalisez l’insertion d’un titulaire complet (dans holder et person) à l’aide d’une transaction. Testez le cas où la contrainte d’âge échoue et vérifiez que rien n’est inséré dans holder.
4. Procédure stockée
Vous avez remarqué qu’en ajoutant une contrainte sur l’âge minimum du titulaire, une insertion invalide dans person peut échouer après la création du holder.
Cela laisse un titulaire orphelin sans fiche personnelle.
Dans un système bancaire réel, ce type d’incohérence est inacceptable. Nous allons donc encapsuler la création d’un titulaire dans une procédure stockée pour garantir la cohérence et la simplicité d’usage.
-
Créez une procédure stockée appelée
create_person_holder-
qui prend en paramètre :
- le prénom (
p_firstname text) - le nom (
p_lastname text) - la date de naissance (
p_birthdate date)
- le prénom (
-
-
Cette procédure doit :
- Vérifier que la personne a au moins 15 ans ;
- Créer automatiquement un enregistrement dans
holder(type ='PERSON') ; - Récupérer l’identifiant généré et créer la fiche dans
person; - Afficher un message de confirmation avec
RAISE NOTICE.
-
Si la personne a moins de 15 ans :
- La procédure doit refuser la création et afficher une erreur claire (par
RAISE EXCEPTION).
- La procédure doit refuser la création et afficher une erreur claire (par
En PL/pgSQL les procédures s’écrivent :
create or replace procedure nom_procedure(paramètres)
language plpgsql
as $$
declare
-- variables locales
begin
-- instructions SQL
end;
$$;
Vous pouvez intercepter une erreur métier à l’aide de :
raise exception 'message';
Pour afficher un message de réussite :
raise notice 'message %', variable;
Pour appeler une procédure stockée
call create_person_holder('Alice', 'Martin', '1990-03-15');
Note
La procédure garantit l’atomicité : soit tout est créé, soit rien.
5. Cohérence des données
Écrire une requête pour vérifier la somme
Excellent 👌 — on va continuer dans la même logique de rigueur comptable et de progressivité pédagogique. Cette étape introduira une seconde procédure stockée, dédiée à la création de comptes, avec contrôle des titulaires associés et de leurs parts (shares).
🧩 TP Banque – Étape 5 : Créer un compte bancaire de manière cohérente
🎯 Objectif
Jusqu’à présent, nous savons créer des titulaires (holder) de façon sûre.
Il est temps de leur ouvrir des comptes bancaires.
Un compte doit toujours :
- être associé à au moins un titulaire,
- et la somme des parts (
share) des titulaires doit être exactement égale à 1 (c’est-à-dire 100 % du compte).
Nous allons donc écrire une procédure stockée create_account qui vérifie ces règles avant d’enregistrer les données.
📘 Contexte
Les tables concernées sont les suivantes :
create table account (
id serial primary key,
iban text not null unique,
name text not null,
opened_on date not null default current_date
);
create table account_holder (
account_id int not null references account(id) on delete cascade,
holder_id int not null references holder(id) on delete restrict,
share numeric(5,4) not null check (share > 0 and share <= 1),
primary key (account_id, holder_id)
);
👉 La table account_holder relie un compte à un ou plusieurs titulaires, avec la part de chacun.
🧱 Travail demandé
-
Créez une procédure stockée
create_accountqui :-
prend en paramètre :
p_iban text,p_name text,p_holders int[](tableau des identifiants de titulaires),p_shares numeric[](tableau des parts correspondantes).
-
vérifie que :
- le nombre d’éléments dans
p_holdersetp_sharesest identique ; - la somme des parts est exactement égale à 1 ;
- chaque
holder_idexiste dans la tableholder.
- le nombre d’éléments dans
-
-
Si tout est correct :
- crée un nouveau compte dans
account; - insère les lignes correspondantes dans
account_holder.
- crée un nouveau compte dans
-
Si une condition échoue :
- la procédure doit lever une erreur explicite (
RAISE EXCEPTION) ; - aucune insertion ne doit être faite (transaction annulée).
- la procédure doit lever une erreur explicite (
-
Les tableaux peuvent être parcourus avec une boucle :
for i in 1..array_length(p_holders, 1) loop ... end loop; -
Pour vérifier la somme :
select sum(unnest(p_shares));(ou additionner dans la boucle)
-
Vous pouvez lever une erreur personnalisée :
raise exception 'La somme des parts doit être égale à 1 (%.4f)', somme;
Exemples d’appel
call create_account(
'FR761234567890',
'Compte commun',
array[1, 5],
array[0.5, 0.5]
);
Crée un compte partagé 50/50 entre les titulaires 1 et 2.
call create_account(
'FR009999999999',
'Compte déséquilibré',
array[1, 5],
array[0.7, 0.4]
);
Doit refuser la création avec une erreur claire :
ERROR: La somme des parts (1.1000) doit être égale à 1.0000