This commit is contained in:
2025-11-02 20:50:39 +01:00
parent 46db8f1e19
commit 1a06ea5bf2
3 changed files with 329 additions and 94 deletions

209
banque.md
View File

@@ -71,3 +71,212 @@ La banque souhaite désormais que toute personne titulaire dun compte ait au
- 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 lon 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 nest pas annulée automatiquement.
Réalisez linsertion dun titulaire complet (dans holder et person) à laide dune transaction.
Testez le cas où la contrainte dâge échoue et vérifiez que rien nest inséré dans holder.
## 4. Procédure stockée
Vous avez remarqué quen 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 dincohérence est inacceptable.
Nous allons donc **encapsuler la création dun titulaire dans une procédure stockée** pour garantir la cohérence et la simplicité dusage.
1. 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`)
2. 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 lidentifiant généré et créer la fiche dans `person` ;
* Afficher un message de confirmation avec `RAISE NOTICE`.
3. Si la personne a moins de 15 ans :
* La procédure doit **refuser la création** et afficher une erreur claire (par `RAISE EXCEPTION`).
En PL/pgSQL les **procédures** sécrivent :
```sql
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 à laide de :
```sql
raise exception 'message';
```
Pour afficher un message de réussite :
```sql
raise notice 'message %', variable;
```
Pour appeler une procédure stockée
```sql
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** (cest-à-dire 100 % du compte).
Nous allons donc écrire une **procédure stockée** `create_account` qui vérifie ces règles avant denregistrer les données.
---
## 📘 Contexte
Les tables concernées sont les suivantes :
```sql
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é
1. Créez une **procédure stockée** `create_account` qui :
* 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_holders` et `p_shares` est identique ;
* la somme des parts est **exactement égale à 1** ;
* chaque `holder_id` existe dans la table `holder`.
2. Si tout est correct :
* crée un nouveau compte dans `account` ;
* insère les lignes correspondantes dans `account_holder`.
3. Si une condition échoue :
* la procédure doit lever une **erreur explicite** (`RAISE EXCEPTION`) ;
* aucune insertion ne doit être faite (transaction annulée).
---
## 💡 Aide
* Les tableaux peuvent être parcourus avec une boucle :
```sql
for i in 1..array_length(p_holders, 1) loop
...
end loop;
```
* Pour vérifier la somme :
```sql
select sum(unnest(p_shares));
```
(ou additionner dans la boucle)
* Vous pouvez lever une erreur personnalisée :
```sql
raise exception 'La somme des parts doit être égale à 1 (%.4f)', somme;
```
---
## ✅ Exemple dappel
### Cas valide :
```sql
call create_account(
'FR761234567890',
'Compte commun',
array[1, 2],
array[0.5, 0.5]
);
```
➡️ Crée un compte partagé 50/50 entre les titulaires 1 et 2.
### Cas invalide :
```sql
call create_account(
'FR009999999999',
'Compte déséquilibré',
array[1, 2],
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
```