Files
sql/banque.md
2025-11-02 20:50:39 +01:00

8.5 KiB
Raw Blame History

Modélisation d'un système bancaire

Objectifs

  • Concevoir un modèle relationnel à partir dun scénario réaliste.
  • Utiliser les contraintes dintégrité pour garantir la cohérence des données.
  • Manipuler des jointures et des relations nn.
  • Comprendre la notion dhé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 dimplémenter le schéma relationnel de base permettant de gérer :

  1. Les clients de la banque, appelés titulaires (holders),
  2. Les comptes bancaires (accounts),
  3. 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 dimmatriculation 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 tables person et company qui héritent logiquement de celle-ci.

1.3 Contraintes à respecter

  • Chaque person ou company doit correspondre à exactement un seul holder.
  • La suppression dun holder doit supprimer automatiquement la ligne correspondante dans person ou company.
  • 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

  1. Pourquoi séparer person et company ?
  2. Pourquoi ne pas tout mettre dans une seule table holder ?
  3. Quelle contrainte empêche dinsérer une person sans holder ?

1.6 Pour aller plus loin

La banque souhaite désormais que toute personne titulaire dun 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 dun numéro de compte (account number) unique, dun 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 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 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 :

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 :

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 latomicité : 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 :

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 :

    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;
    

Exemple dappel

Cas valide :

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 :

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