2025-11-02 14:36:58 +01:00
# Modélisation d'un système bancaire
2025-11-02 09:24:15 +01:00
2025-11-05 07:43:14 +01:00
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 :
1. Les clients de la banque,
2. Les comptes bancaires,
2025-11-06 09:35:06 +01:00
3. Le lien entre les clients et les comptes.
2025-11-05 13:47:17 +01:00
4. Les dépots et les retraits d'argent.
5. Les virements entre compte.
6. Les devises et les taux de change.
2025-11-05 07:43:14 +01:00
L'objectif de ces travaux pratiques est de :
2025-11-02 14:36:58 +01:00
- 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.
2025-11-05 07:43:14 +01:00
La diffusion de cette application est internationale, vous vous efforcerez d'utiliser des termes anglais pour nommer les entités et les propriétés. Réferrez pour cela vous au [glossaire ](banque.glossaire.md )
2025-11-02 14:36:58 +01:00
2025-11-05 07:43:14 +01:00
Pour les entités vous utiliserez le singuler et écrirez le tout en minuscule.
2025-11-02 14:36:58 +01:00
2025-11-07 07:13:51 +01:00
## Séance 1 : Le Diagramme Entités Relations (ERD)
2025-11-06 09:35:06 +01:00
### 1. Les titulaires
2025-11-02 14:36:58 +01:00
2025-11-07 08:45:54 +01:00
Un client de la banque est appelé un titulaire. Il peut être une **personne physique ** ou une **entreprise ** .
2025-11-02 14:36:58 +01:00
- 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.
2025-11-03 13:42:34 +01:00
#### Pourquoi séparer `person` et `company` ?
2025-11-02 14:36:58 +01:00
2025-11-03 13:42:34 +01:00
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.
2025-11-02 14:36:58 +01:00
2025-11-03 13:42:34 +01:00
#### Quelle contrainte empêche d’ insérer une person sans holder ?
2025-11-02 14:36:58 +01:00
2025-11-03 13:42:34 +01:00
La clé étrangère `references holder(id)` dans `person` .
2025-11-02 14:36:58 +01:00
2025-11-05 16:25:35 +01:00
```mermaid
erDiagram
2025-11-08 06:15:58 +01:00
person {
bigint id PK
text firstname
text lastname
date birthdate
}
company {
bigint id PK
text name
text registration_number
date creation_date
}
holder {
bigint id PK
timestamp creation_date
text type
}
2025-11-05 16:25:35 +01:00
2025-11-06 06:51:21 +01:00
%% Relations
2025-11-05 16:25:35 +01:00
2025-11-06 09:35:06 +01:00
person |o--|| holder : is
company |o--|| holder : is
2025-11-05 16:25:35 +01:00
```
2025-11-07 07:13:51 +01:00
### 2. Les comptes
2025-11-02 14:36:58 +01:00
2025-11-07 08:58:35 +01:00
- Chaque titulaire peut détenir **un ** ou **plusieurs comptes ** .
- Un compte bancaire doit pouvoir appartenir à **un ** ou **plusieurs titulaires ** (compte individuel / compte joint).
- Chaque compte dispose d’ un numéro de compte unique, d’ un solde et d'une date d'ouverture.
- Dans le cas d'un compte joint, les parts de propriété d'un compte doivent pouvoir être précisées.
2025-11-02 16:21:22 +01:00
2025-11-07 07:03:42 +01:00
```mermaid
erDiagram
person {
bigint id PK
text firstname
text lastname
date birthdate
}
2025-11-02 16:21:22 +01:00
2025-11-07 07:03:42 +01:00
company {
bigint id PK
2025-11-07 14:44:02 +01:00
text name
2025-11-07 07:03:42 +01:00
text registration_number
date creation_date
}
holder {
bigint id PK
2025-11-07 14:41:11 +01:00
timestamp creation_date
2025-11-07 07:03:42 +01:00
text type
}
account {
bigint id PK
2025-11-07 18:33:08 +01:00
timestamp creation_date
2025-11-07 07:03:42 +01:00
decimal balance
}
account_holder {
bigint account_id FK
bigint holder_id FK
decimal share
}
2025-11-02 20:50:39 +01:00
2025-11-07 07:03:42 +01:00
%% Relations
person |o--|| holder : is
company |o--|| holder : is
holder }|--|{ account_holder : a
2025-11-08 06:15:58 +01:00
account_holder ||--|{ account : hold
2025-11-07 07:03:42 +01:00
```
### 3. Les opérations
2025-11-02 20:50:39 +01:00
2025-11-06 06:51:21 +01:00
```mermaid
erDiagram
person {
bigint id PK
text firstname
text lastname
date birthdate
}
company {
bigint id PK
2025-11-07 14:44:02 +01:00
text name
2025-11-06 09:35:06 +01:00
text registration_number
2025-11-06 06:51:21 +01:00
date creation_date
}
2025-11-07 18:33:08 +01:00
bank {
bigint id PK
text name
}
2025-11-06 06:51:21 +01:00
holder {
bigint id PK
2025-11-07 14:41:11 +01:00
timestamp creation_date
2025-11-06 09:35:06 +01:00
text type
2025-11-06 06:51:21 +01:00
}
account {
bigint id PK
2025-11-07 18:33:08 +01:00
timestamp creation_date
2025-11-06 07:17:31 +01:00
decimal balance
2025-11-06 06:51:21 +01:00
text currency_code FK
}
account_holder {
bigint account_id FK
bigint holder_id FK
2025-11-06 07:17:31 +01:00
decimal share
2025-11-06 06:51:21 +01:00
}
2025-11-07 07:03:42 +01:00
2025-11-06 09:35:06 +01:00
operation {
2025-11-06 06:51:21 +01:00
bigint id PK
2025-11-06 09:35:06 +01:00
bigint transaction_id FK
2025-11-07 18:33:08 +01:00
bigint account_id FK
2025-11-06 06:51:21 +01:00
decimal amount
2025-11-06 09:35:06 +01:00
text direction
2025-11-06 06:51:21 +01:00
}
2025-11-06 09:35:06 +01:00
%% Relations
person |o--|| holder : is
company |o--|| holder : is
bank |o--|| holder : is
2025-11-07 07:03:42 +01:00
holder }|--|{ account_holder : a
2025-11-08 06:15:58 +01:00
account_holder ||--|{ account : hold
2025-11-07 07:03:42 +01:00
operation }o--|| account : concerne
2025-11-06 09:35:06 +01:00
```
2025-11-06 10:01:02 +01:00
### 4. Les transactions
2025-11-07 07:13:51 +01:00
#### La double écriture comptable
Jusqu’ à présent, les dépôts et retraits modifiaient directement le solde d’ un compte.
Mais dans un vrai système bancaire ou comptable, chaque opération financière doit être enregistrée en double :
- Un débit sur un compte (celui qui reçoit)
- Un crédit sur un autre (celui qui cède)
La somme des débits doit toujours être égale à la somme des crédits.
2025-11-06 10:01:02 +01:00
Chaque opération comporte au moins :
* un **compte concerné ** ;
* une **date ** ;
* un **montant ** ;
* un **sens ** (débit ou crédit).
2025-11-07 13:07:30 +01:00
#### Méthode 1 : montant relatif (positif/négatif)
2025-11-06 10:01:02 +01:00
2025-11-07 07:03:42 +01:00
On stocke un seul champ `montant` .
* **Crédit** → montant positif
* **Débit** → montant négatif
2025-11-07 07:13:51 +01:00
##### Exemple
2025-11-06 10:01:02 +01:00
| id | compte | date | montant |
| -- | ------ | ---------- | ------- |
| 1 | 123 | 2025-11-06 | +200.00 |
| 2 | 123 | 2025-11-07 | -50.00 |
2025-11-07 07:13:51 +01:00
##### Avantages
2025-11-06 10:01:02 +01:00
* **Simple à manipuler** pour les calculs (sommes, soldes, agrégations).
* Pas besoin de colonne supplémentaire pour le sens.
* Représente naturellement le comportement du solde d’ un compte.
2025-11-07 07:13:51 +01:00
##### Inconvénients
2025-11-06 10:01:02 +01:00
* Le **signe a une signification métier ** implicite → risque d’ erreur d’ interprétation.
* **Moins lisible** pour les utilisateurs finaux ou pour des exports comptables.
* Pas toujours compatible avec les règles de la **comptabilité en partie double ** (où débit et crédit doivent être visibles séparément).
2025-11-07 13:07:30 +01:00
#### Méthode 2 : deux colonnes (débit / crédit)
2025-11-06 10:01:02 +01:00
2025-11-07 07:03:42 +01:00
Deux colonnes numériques, l’ une pour le débit, l’ autre pour le crédit.
Une seule des deux contient une valeur non nulle.
2025-11-07 07:13:51 +01:00
##### Exemple
2025-11-06 10:01:02 +01:00
| id | compte | date | debit | credit |
| -- | ------ | ---------- | ----- | ------ |
| 1 | 123 | 2025-11-06 | 0.00 | 200.00 |
| 2 | 123 | 2025-11-07 | 50.00 | 0.00 |
2025-11-07 07:13:51 +01:00
##### Avantages
2025-11-06 10:01:02 +01:00
* Très **clair visuellement ** et **conforme aux usages comptables ** .
* Facilite les **exports vers des logiciels comptables ** .
* On peut facilement filtrer les débits et crédits séparément.
2025-11-07 07:13:51 +01:00
##### Inconvénients
2025-11-06 10:01:02 +01:00
* **Redondance potentielle** (une des deux colonnes sera toujours à zéro).
* Les calculs de soldes nécessitent des **expressions plus complexes ** :
`SUM(credit) - SUM(debit)`
* Risque d’ incohérence si les deux colonnes contiennent des valeurs remplies par erreur.
2025-11-07 13:07:30 +01:00
#### Méthode 3 : montant absolu + colonne sens ('D' / 'C')
2025-11-06 10:01:02 +01:00
2025-11-07 07:03:42 +01:00
Le montant est toujours positif.
Le sens est indiqué par une lettre (`D` ou `C` ).
2025-11-07 07:13:51 +01:00
##### Exemple
2025-11-06 10:01:02 +01:00
| id | compte | date | montant | sens |
| -- | ------ | ---------- | ------- | ---- |
| 1 | 123 | 2025-11-06 | 200.00 | C |
| 2 | 123 | 2025-11-07 | 50.00 | D |
2025-11-07 07:13:51 +01:00
##### Avantages
2025-11-06 10:01:02 +01:00
* **Lisible** et **intuitif ** : correspond au vocabulaire métier.
* Facilite la lecture humaine et les exports comptables.
* Pas d’ ambiguïté sur le signe numérique.
2025-11-07 07:13:51 +01:00
##### Inconvénients
2025-11-06 10:01:02 +01:00
* Nécessite une **jointure logique ** du sens pour les calculs :
`SUM(CASE WHEN sens='C' THEN montant ELSE -montant END)`
* Moins direct pour les traitements purement mathématiques.
* L’ usage de lettres rend le **stockage un peu moins compact ** (mais négligeable en pratique).
2025-11-07 13:07:30 +01:00
#### Méthode 4 : montant absolu + colonne sens numérique (1 / -1)
2025-11-06 10:01:02 +01:00
2025-11-07 07:03:42 +01:00
Le montant est toujours positif, et une colonne numérique `sens` vaut `1` (crédit) ou `-1` (débit).
2025-11-07 07:13:51 +01:00
##### Exemple
2025-11-06 10:01:02 +01:00
| id | compte | date | montant | sens |
| -- | ------ | ---------- | ------- | ---- |
| 1 | 123 | 2025-11-06 | 200.00 | 1 |
| 2 | 123 | 2025-11-07 | 50.00 | -1 |
2025-11-07 07:13:51 +01:00
##### Avantages
2025-11-06 10:01:02 +01:00
* **Compact et performant** pour les calculs :
`SUM(montant * sens)` donne directement le solde.
* Moins d’ ambiguïté qu’ un signe caché dans le montant.
* Combine la **rigueur du modèle mathématique ** avec la **clarté du stockage absolu ** .
2025-11-07 07:13:51 +01:00
##### Inconvénients
2025-11-06 10:01:02 +01:00
* **Moins lisible** pour un utilisateur non technique.
* Moins standard pour la comptabilité classique (on préfère `D` / `C` ).
* Nécessite une convention claire sur la signification de `1` et `-1` .
2025-11-07 07:13:51 +01:00
#### Synthèse comparative
2025-11-06 10:01:02 +01:00
2025-11-07 08:58:35 +01:00
| Méthode | Structure | Lisibilité | Facilité calculs | Conformité comptable | Risque d'erreur |
| ------- | ---------------------- | ------------| ---------------- | -------------------- | --------------- |
2025-11-06 10:01:02 +01:00
| 1 | montant relatif (+/-) | ★☆☆ | ★★★ | ★☆☆ | Moyen |
| 2 | débit / crédit séparés | ★★★ | ★☆☆ | ★★★ | Faible |
| 3 | valeur + sens 'D'/'C' | ★★★ | ★★☆ | ★★★ | Faible |
| 4 | valeur + sens 1/-1 | ★★☆ | ★★★ | ★★☆ | Moyen |
### 5. Les devises
2025-11-06 09:35:06 +01:00
```mermaid
erDiagram
person {
bigint id PK
text firstname
text lastname
date birthdate
}
company {
bigint id PK
2025-11-07 14:44:02 +01:00
text name
2025-11-06 09:35:06 +01:00
text registration_number
date creation_date
}
bank {
bigint id PK
2025-11-07 14:41:11 +01:00
text name
2025-11-06 09:35:06 +01:00
}
holder {
bigint id PK
2025-11-07 14:41:11 +01:00
timestamp creation_date
2025-11-06 09:35:06 +01:00
text type
2025-11-06 06:51:21 +01:00
}
2025-11-06 09:35:06 +01:00
account {
bigint id PK
2025-11-07 18:33:08 +01:00
timestamp creation_date
2025-11-06 09:35:06 +01:00
decimal balance
text currency_code FK
}
account_holder {
2025-11-07 21:29:15 +01:00
bigint account_id PK,FK
bigint holder_id PK,FK
2025-11-06 09:35:06 +01:00
decimal share
}
2025-11-07 07:03:42 +01:00
2025-11-06 06:51:21 +01:00
currency {
text code PK
}
2025-11-06 06:58:42 +01:00
exchange_rate {
date date PK
2025-11-07 21:29:15 +01:00
text currency_code PK,FK
2025-11-06 06:58:42 +01:00
decimal rate
}
2025-11-06 06:51:21 +01:00
2025-11-06 07:13:27 +01:00
transaction {
bigint id PK
2025-11-07 20:55:42 +01:00
timestamp transaction_date
2025-11-06 07:13:27 +01:00
decimal amount
}
2025-11-06 07:17:31 +01:00
operation {
bigint id PK
2025-11-06 09:35:06 +01:00
bigint transaction_id FK
2025-11-07 17:33:51 +01:00
bigint account_id FK
2025-11-06 07:17:31 +01:00
decimal amount
text direction
}
2025-11-06 06:58:42 +01:00
%% Relations
2025-11-06 06:51:21 +01:00
2025-11-06 09:35:06 +01:00
person |o--|| holder : is
company |o--|| holder : is
bank |o--|| holder : is
2025-11-06 07:22:45 +01:00
holder }|--|{ account_holder : a
2025-11-08 06:15:58 +01:00
account_holder ||--|{ account : hold
2025-11-06 07:27:31 +01:00
currency ||--|{ account : tenu
2025-11-06 07:22:45 +01:00
exchange_rate }o--|| currency : a
2025-11-08 13:10:09 +01:00
transaction ||--|{ operation : a
operation }o--|| account : a
2025-11-06 06:51:21 +01:00
```
2025-11-07 07:03:42 +01:00
---
2025-11-07 13:07:30 +01:00
# Séance 2 : Implémentation du modèle
2025-11-07 13:49:27 +01:00
Voir les adresses des serveurs [postgreSQL ](https://sources.neotech.fr/Universite/tp/src/branch/main/geii3_2025.md )
2025-11-08 05:51:25 +01:00
Voir la syntaxe de [postgreSQL ](syntaxe.md )
2025-11-07 07:45:45 +01:00
### 1. Titulaires
2025-11-07 07:03:42 +01:00
2025-11-08 13:10:09 +01:00
Création de la table `holder` .
```sql
create table holder (
"id" bigint primary key generated always as identity,
"type" text,
"created_at" timestamp
);
```
- entier sur 64 bits : `bigint`
- clé primaire : `primary key`
- incrément automatique : `generated always as identity`
Création de la table `person` .
```sql
create table person (
"id" bigint primary key references holder(id),
"firstname" text,
"lastname" text,
"birthdate" date
);
```
2025-11-07 08:45:54 +01:00
- Créer un compte individuel pour _ Françoise Zanetti _ , née le 12 avril 1995.
- Créer une entreprise nommée _ Boulangerie de Valorgue _ , créée le 19 août 2014, numéro d’ immatriculation FR19803269968.
- Ajouter un nouveau titulaire : _ Justin Hébrard _ né le 11/03/1993.
2025-11-07 07:03:42 +01:00
2025-11-15 09:33:22 +01:00
```sql
create table company (
"id" bigint primary key references holder(id),
"name" text,
"creation_date" date
);
```
2025-11-08 14:56:53 +01:00
```sql
create table bank (
"id" bigint primary key references holder(id),
"name" text
);
```
```sql
insert into holder (type) values ('BANK') returning holder;
```
```sql
2025-11-14 23:02:00 +01:00
insert into bank (id, name) values (1, 'Banque de l''Est');
2025-11-08 14:56:53 +01:00
```
2025-11-07 07:45:45 +01:00
#### 1.1 Contraintes à respecter
- Chaque `person` ou `company` doit correspondre à exactement un seul `holder` .
- La suppression d’ un `holder` doit supprimer automatiquement la ligne correspondante dans `person` ou `company` .
2025-11-08 05:51:25 +01:00
- 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é.
2025-11-07 07:45:45 +01:00
- Le type doit être contraint à `'PERSON'` ou `'COMPANY'` .
2025-11-07 11:11:08 +01:00
Il existe deux méthodes pour gérer le type.
1. vérifier par la commande `CHECK` la validité de la valeur.
2. utiliser une énumération `enum` .
2025-11-09 10:26:00 +01:00
```sql
create type holder_type as enum ('BANK', 'PERSON', 'COMPANY');
```
2025-11-07 11:11:08 +01:00
2025-11-07 07:45:45 +01:00
#### 1.2 Vérifications
2025-11-06 09:35:06 +01:00
- 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.
2025-11-07 13:07:30 +01:00
#### 1.4 L'intégrité des données
2025-11-06 09:35:06 +01:00
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 ** .
Testez le cas où la contrainte d’ âge échoue et vérifiez que rien n’ est inséré dans holder.
```sql
begin;
...
commit;
```
2025-11-07 13:07:30 +01:00
#### 1.5 Procédure stockée
2025-11-02 20:50:39 +01:00
2025-11-03 13:42:34 +01:00
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 ** .
2025-11-02 20:50:39 +01:00
2025-11-07 13:07:30 +01:00
Créez une **procédure stockée ** appelée `create_person_holder` .
2025-11-02 20:50:39 +01:00
2025-11-03 13:42:34 +01:00
Cette procédure prend en paramètre :
2025-11-02 20:50:39 +01:00
2025-11-03 13:42:34 +01:00
* le prénom (`p_firstname text` )
* le nom (`p_lastname text` )
* la date de naissance (`p_birthdate date` )
2025-11-02 20:50:39 +01:00
2025-11-03 13:42:34 +01:00
Cette procédure doit :
2025-11-02 20:50:39 +01:00
2025-11-03 13:42:34 +01:00
* 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.
2025-11-02 20:50:39 +01:00
3. Si la personne a moins de 15 ans :
2025-11-03 13:42:34 +01:00
* La procédure doit **refuser la création ** et afficher une erreur claire.
2025-11-02 20:50:39 +01:00
>[!NOTE]
> La procédure garantit l’ **atomicité** : soit tout est créé, soit rien.
2025-11-07 13:07:30 +01:00
### 2. Les comptes
2025-11-02 20:50:39 +01:00
2025-11-08 13:23:25 +01:00
```sql
create table account (
"id" bigint primary key generated always as identity,
"creation_date" date default current_date,
"balance" decimal check (balance >= 0),
"currency_code" text references currency (code)
);
```
2025-11-07 13:07:30 +01:00
- Le solde des comptes ne peuvent être négatifs.
2025-11-07 08:45:54 +01:00
- Créez un compte joint à 50/50 pour Françoise et Justin.
2025-11-03 13:42:34 +01:00
Écrire une requête pour vérifier la somme des parts
2025-11-02 20:50:39 +01:00
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.
1. Créez une **procédure stockée ** `create_account` qui :
2025-11-03 13:42:34 +01:00
* prend en paramètre :
* `p_holders int[]` (tableau des identifiants de titulaires),
* `p_shares numeric[]` (tableau des parts correspondantes).
2025-11-02 20:50:39 +01:00
2025-11-03 13:42:34 +01:00
* vérifie que :
2025-11-02 20:50:39 +01:00
2025-11-03 13:42:34 +01:00
* 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` .
2025-11-02 20:50:39 +01:00
2. Si tout est correct :
2025-11-03 13:42:34 +01:00
* crée un nouveau compte dans `account` ;
* insère les lignes correspondantes dans `account_holder` .
2025-11-02 20:50:39 +01:00
3. Si une condition échoue :
2025-11-03 13:42:34 +01:00
* la procédure doit lever une **erreur explicite ** (`RAISE EXCEPTION` ) ;
* aucune insertion ne doit être faite (transaction annulée).
2025-11-02 20:50:39 +01:00
* Les tableaux peuvent être parcourus avec une boucle :
2025-11-03 13:42:34 +01:00
```sql
for i in 1..array_length(p_holders, 1) loop
...
end loop;
```
2025-11-02 20:50:39 +01:00
* Pour vérifier la somme :
2025-11-03 13:42:34 +01:00
```sql
select sum(unnest(p_shares));
```
2025-11-02 20:50:39 +01:00
(ou additionner dans la boucle)
* Vous pouvez lever une erreur personnalisée :
2025-11-03 13:42:34 +01:00
```sql
raise exception 'La somme des parts doit être égale à 1 (%.4f)', somme;
```
2025-11-02 20:50:39 +01:00
2025-11-07 07:13:51 +01:00
#### Exemples d’ appel
2025-11-02 20:50:39 +01:00
```sql
call create_account(
'FR761234567890',
'Compte commun',
2025-11-03 07:06:56 +01:00
array[1, 5],
2025-11-02 20:50:39 +01:00
array[0.5, 0.5]
);
```
2025-11-03 07:06:56 +01:00
Crée un compte partagé 50/50 entre les titulaires 1 et 2.
2025-11-02 20:50:39 +01:00
```sql
call create_account(
'FR009999999999',
'Compte déséquilibré',
2025-11-03 07:06:56 +01:00
array[1, 5],
2025-11-02 20:50:39 +01:00
array[0.7, 0.4]
);
```
2025-11-03 07:06:56 +01:00
Doit refuser la création avec une erreur claire :
2025-11-02 20:50:39 +01:00
```
ERROR: La somme des parts (1.1000) doit être égale à 1.0000
```
2025-11-08 13:23:25 +01:00
### 3. Monnaies et taux de change
2025-11-07 13:07:30 +01:00
2025-11-08 13:23:25 +01:00
```sql
create table currency (
2025-11-08 13:39:12 +01:00
"code" text primary key
2025-11-08 13:23:25 +01:00
);
```
2025-11-08 13:39:12 +01:00
```sql
insert into currency values ('EUR');
insert into currency values ('YEN');
```
2025-11-08 13:23:25 +01:00
```sql
create table exchange_rate (
"currency_code" text references currency(code) on delete cascade,
"date" date ,
"rate" decimal not null,
primary key (currency_code, date)
);
```
2025-11-08 13:39:12 +01:00
```sql
insert into exchange_rate values
('YEN', '2025-11-03', 177.57),
('YEN', '2025-11-04', 176.39),
('YEN', '2025-11-05', 176.67),
('YEN', '2025-11-06', 177.15),
('YEN', '2025-11-07', 176.99);
```
2025-11-08 13:23:25 +01:00
### 4. Les opérations et transactions
2025-11-07 13:07:30 +01:00
Implémenter les transactions et opérations.
2025-11-08 13:23:25 +01:00
```sql
create table transaction (
"id" bigint primary key generated always as identity,
"transaction_date" timestamp default current_timestamp,
2025-11-08 13:39:12 +01:00
"amount" decimal check (amount > 0)
2025-11-08 13:23:25 +01:00
);
```
```sql
create table operation (
"id" bigint primary key generated always as identity,
"transaction_id" bigint references transaction(id),
"account_id" bigint references account(id),
2025-11-08 13:39:12 +01:00
"amount" decimal check (amount > 0),
"direction" text check (direction in ('DEBIT', 'CREDIT'))
2025-11-08 13:23:25 +01:00
);
```
2025-11-14 07:32:20 +01:00
2025-11-15 09:33:22 +01:00
#### Dépôts et retraits
```sql
create or replace procedure add_retrait (
p_account_id bigint,
p_amount decimal
)
language plpgsql
as $$
declare
v_id bigint
begin
end;
$$;
```
2025-11-14 07:32:20 +01:00
# Séance 3 : Exploitation des données
2025-11-14 14:25:28 +01:00
Ajouter des données
2025-11-14 07:32:20 +01:00
2025-11-14 14:25:28 +01:00
```sql
truncate table holder;
truncate table account;
call add_bank('Banque de l''Est');
insert into currency values ('EUR'),('YEN'),('USD');
call add_account(1,'EUR');
call add_account(1,'YEN');
call add_account(1,'USD');
update account set balance = 100000 where id = 1;
update account set balance = 50000 where id = 2;
update account set balance = 200000 where id = 3;
insert into exchange_rate values
('EUR', '1999-01-01', 1),
('USD', '2025-01-02', 1.0321),
('USD', '2025-02-03', 1.0274),
('USD', '2025-03-03', 1.0465);
```
2025-11-14 16:26:31 +01:00
## 1. Vue : taux de change de la veille
2025-11-14 14:25:28 +01:00
2025-11-14 16:26:31 +01:00
Créer une vue * yesterday_exchange_rates * qui affiche pour **chaque devise ** son taux de change de la veille présent dans `exchange_rate` .
2025-11-14 14:25:28 +01:00
Si aucun taux du jour n’ existe, la ligne ne doit pas apparaître.
2025-11-14 16:26:31 +01:00
## 2. Fonction : dernier taux connu pour une devise et une date données
Créer une fonction * latest_exchange_rate * qui donne, pour une devise, son taux de change le plus récent :
## 3. Vue : liste détaillées des titulaires
2025-11-14 07:32:20 +01:00
Créer une vue * holder_details * permettant d’ afficher **tous les titulaires ** (banque, personne ou entreprise) sous une forme unifiée.
La vue doit contenir :
* l’ identifiant du titulaire
* son type
* un champ `display_name` calculé ainsi :
* pour un titulaire de type * PERSON * : * firstname lastname *
* pour un titulaire de type * COMPANY * : * name *
* pour un titulaire de type * BANK * : * name *
2025-11-14 16:26:31 +01:00
## 4. Vue : liste des comptes avec devise et solde
2025-11-14 07:32:20 +01:00
2025-11-14 23:02:00 +01:00
Créer une vue * account_detail * affichant :
2025-11-14 07:32:20 +01:00
* l’ identifiant du compte
* la date d’ ouverture
* la devise
* le solde
* le nombre de titulaires du compte
2025-11-14 16:26:31 +01:00
## 5. Vue : comptes par titulaire
2025-11-14 07:32:20 +01:00
Créer une vue * holder_accounts * permettant de lister les comptes détenus par chaque titulaire, avec :
* le titulaire (id et type)
* le nom du titulaire
* l’ identifiant du compte
* la part détenue (`share` )
* le solde total du compte
La vue doit fusionner les informations venant de **holder, person et company ** .
2025-11-14 16:26:31 +01:00
## 6. Vue : opérations enrichies
2025-11-14 07:32:20 +01:00
Créer une vue * operation_details * affichant les opérations avec :
* la date de l’ opération
* le compte impacté
* la direction (DEBIT ou CREDIT)
* le montant de l’ opération
* le montant signé (crédit positif, débit négatif)
* le solde du compte **après l’ opération ** (bonus : fenêtre analytique)
2025-11-14 16:26:31 +01:00
## 7. Vue : solde converti en EUR
2025-11-14 07:32:20 +01:00
Créer une vue * account_balance_eur * pour afficher :
* compte
* devise d’ origine
* solde original
* taux de change correspondant à la date du jour
* solde converti en EUR (solde × taux)
2025-11-14 16:26:31 +01:00
## 8. Vue : transactions complètes
2025-11-14 07:32:20 +01:00
Créer une vue * transaction_summary * affichant un regroupement par transaction :
* id de la transaction
* date
* montant total de la transaction (somme des opérations)
* liste des comptes concernés (optionnel : concaténation)
2025-11-14 16:26:31 +01:00
## 9. Vue : comptes en découvert imminent
2025-11-14 07:32:20 +01:00
Créer une vue * accounts_at_risk * listant les comptes dont le solde est inférieur à 50 (dans leur devise), ou qui auraient un solde négatif s'ils effectuaient un débit supplémentaire de 20.
> Vérification simple : `balance - 20 < 0 OR balance < 50`.
2025-11-14 16:26:31 +01:00
## 10. Vue : âge des personnes
2025-11-14 07:32:20 +01:00
Créer une vue * person_age * indiquant :
* id
* nom complet
* date de naissance
* âge en années (utiliser `age()` )
2025-11-14 16:26:31 +01:00
## 11. Vue : répartition des parts d’ un compte
2025-11-14 07:32:20 +01:00
Créer une vue * account_shares * affichant :
* id du compte
* nombre de titulaires
* somme des parts
* une colonne booléenne `is_valid` vérifiant si la somme = 1
> Objectif : vérifier que les parts des comptes joints sont bien réparties.
2025-11-14 16:26:31 +01:00
## 12. Vue : solde par titulaire
2025-11-14 07:32:20 +01:00
Créer une vue * holder_total_balance * indiquant pour chaque titulaire :
* id
* type
* nom
* somme des soldes de tous ses comptes (pondérée par `share` ), calcul :
`total = SUM(share × balance)`
2025-11-14 16:26:31 +01:00
## 13. Vue : opérations d’ un compte en sens unique
2025-11-14 07:32:20 +01:00
Créer une vue * account_debits * listant uniquement les opérations de type DEBIT, avec :
* date
* compte
* montant négatif
Créer une seconde vue * account_credits * (montants positifs).
2025-11-14 16:26:31 +01:00
## 14. Vue : liste des entreprises avec ancienneté
2025-11-14 07:32:20 +01:00
Créer une vue * company_age * indiquant :
* id
* name
* registration_number
* age de l’ entreprise en années (`age(current_date, created_at)` )
2025-11-14 16:26:31 +01:00
## 15. Vue : recapitulatif bancaire complet
2025-11-14 07:32:20 +01:00
Créer une vue * bank_overview * qui croise :
* les titulaires
* leurs comptes
* leurs transactions
* leurs opérations