From 80b74d724ba38e4c0b66b4487dbadc6dd5d4456a Mon Sep 17 00:00:00 2001 From: medina5 Date: Mon, 3 Nov 2025 13:42:34 +0100 Subject: [PATCH] banque 6 --- banque.correction.md | 12 --- banque.md | 185 +++++++++++++++++-------------------------- banque.sql | 2 - 3 files changed, 73 insertions(+), 126 deletions(-) diff --git a/banque.correction.md b/banque.correction.md index 055402f..91e6b4c 100644 --- a/banque.correction.md +++ b/banque.correction.md @@ -10,18 +10,6 @@ - raison sociale, numéro d’immatriculation, date de création -#### 1.5.1 Pourquoi séparer `person` et `company` ? - -Parce que leurs attributs diffèrent (nom/prénom vs raison sociale). -Cela évite les colonnes inutiles et permet des contraintes spécifiques à chaque type. - -#### 1.5.2 Pourquoi ne pas tout mettre dans une seule table holder ? - -Cela forcerait la présence de nombreuses colonnes nulles. La séparation améliore la cohérence et la lisibilité du schéma. - -#### 1.5.3 Quelle contrainte empêche d’insérer une person sans holder ? - -La clé étrangère references holder(id) dans person. ### 1.6 Contôle de l'âge diff --git a/banque.md b/banque.md index ea610b1..7350d3a 100644 --- a/banque.md +++ b/banque.md @@ -1,16 +1,11 @@ # 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. +Une banque locale souhaite informatiser la gestion de ses titulaires et de leurs comptes. Vous êtes chargé(e) de concevoir et d’implémenter le schéma relationnel de base permettant de gérer : @@ -25,7 +20,7 @@ Un titulaire (_holder_) peut être une personne physique (_person_) ou une entre ### 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. +- une entreprise nommée _Boulangerie de Valorgue_, créée le 19 août 2014, numéro d’immatriculation FR19803269968. ### 1.2 Analyse @@ -44,19 +39,23 @@ Un titulaire (_holder_) peut être une personne physique (_person_) ou une entre ### 1.4 Vérifications -Lister tous les titulaires. +- Lister tous les titulaires. Pour réutiliser rapidement la requête enregistrer la dans une vue. +- Supprimer un titulaire, vérifier que cela supprime l'individu ou la société correspondante. -Supprimer un titulaire, vérifier que cela supprime l'individu ou la société correspondante. +### 1.5 Pour aller plus loin -### 1.5 Réflexion +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. Il n'y a pas de restriction sur l'âge de la société. -1. Pourquoi séparer `person` et `company` ? -2. Pourquoi ne pas tout mettre dans une seule table holder ? -3. Quelle contrainte empêche d’insérer une person sans holder ? +### 1.6 Conclusion -### 1.6 Pour aller plus loin +#### Pourquoi séparer `person` et `company` ? -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. +Parce que leurs attributs diffèrent (nom/prénom vs raison sociale). +Cela évite les **colonnes inutiles** et permet des **contraintes spécifiques** à chaque type. + +#### Quelle contrainte empêche d’insérer une person sans holder ? + +La clé étrangère `references holder(id)` dans `person`. ## 2. Les comptes @@ -70,44 +69,46 @@ La banque souhaite désormais que toute personne titulaire d’un 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. +- Créez un compte joint à 50/50 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. +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 du titulaire est toujours présente **sans être rattachée** à une personne. On parle alors d'enregistrement **orphelin**. 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. +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. +```sql +begin; +... +commit; +``` + ## 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. +Pour fiabiliser le process et être sûr que l'execution s'effectue toujours dans une transaction, +nous allons encapsuler la création d’un titulaire dans une **procédure stockée**. -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`. -1. Créez une **procédure stockée** appelée `create_person_holder` +Cette procédure prend en paramètre : - * 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 (`p_firstname text`) - * le nom (`p_lastname text`) - * la date de naissance (`p_birthdate date`) +Cette procédure doit : -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 l’identifiant généré et créer la fiche dans `person` ; - * Afficher un message de confirmation avec `RAISE NOTICE`. + * Vérifier que la personne a **au moins 15 ans** ; + * Créer automatiquement un enregistrement dans `holder` de type `'PERSON'`; + * Récupérer l’identifiant généré et créer la fiche dans `person` ; + * Afficher un message de confirmation. 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`). - + * La procédure doit **refuser la création** et afficher une erreur claire. En PL/pgSQL les **procédures** s’écrivent : @@ -123,22 +124,22 @@ En PL/pgSQL les **procédures** s’écrivent : $$; ``` -Vous pouvez intercepter une erreur métier à l’aide de : - - ```sql - raise exception 'message'; - ``` - Pour afficher un message de réussite : - ```sql - raise notice 'message %', variable; - ``` +```sql +raise notice 'message %', variable; +``` -Pour appeler une procédure stockée +Vous pouvez déclencher une erreur métier à l’aide de : ```sql -call create_person_holder('Alice', 'Martin', '1990-03-15'); +raise exception 'message'; +``` + +Pour appeler la procédure stockée + +```sql +call create_person_holder('Félicien', 'Hébrard', '1970-10-15'); ``` >[!NOTE] @@ -146,18 +147,7 @@ call create_person_holder('Alice', 'Martin', '1990-03-15'); ## 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 +Écrire une requête pour vérifier la somme des parts Jusqu’à présent, nous savons créer des titulaires (`holder`) de façon sûre. Il est temps de leur ouvrir des **comptes bancaires**. @@ -169,81 +159,52 @@ Un compte doit toujours : 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 : - -```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 : + * 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 : + * `p_iban text`, + * `p_name text`, + * `p_holders int[]` (tableau des identifiants de titulaires), + * `p_shares numeric[]` (tableau des parts correspondantes). - * 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`. + * 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`. + * 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). + * la procédure doit lever une **erreur explicite** (`RAISE EXCEPTION`) ; + * aucune insertion ne doit être faite (transaction annulée). * Les tableaux peuvent être parcourus avec une boucle : - ```sql - for i in 1..array_length(p_holders, 1) loop - ... - end loop; - ``` +```sql +for i in 1..array_length(p_holders, 1) loop + ... +end loop; +``` * Pour vérifier la somme : - ```sql - select sum(unnest(p_shares)); - ``` +```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; - ``` - ---- +```sql +raise exception 'La somme des parts doit être égale à 1 (%.4f)', somme; +``` ### Exemples d’appel diff --git a/banque.sql b/banque.sql index 4ca5145..ebf2f77 100644 --- a/banque.sql +++ b/banque.sql @@ -369,5 +369,3 @@ END; $$; - -