This commit is contained in:
2025-11-02 14:36:58 +01:00
parent 928c94e9c8
commit ace5f22f93
4 changed files with 185 additions and 9 deletions

5
Reponses.md Normal file
View File

@@ -0,0 +1,5 @@
SELECT data->>'sku' AS sku,
data->'manufacturer'->>'name' AS marque
FROM products;
db.commandes.find({ reference: '51943385-B' })

114
banque.correction.md Normal file
View File

@@ -0,0 +1,114 @@
# Corrections
## 1. Les titulaires
`holder` : table commune à tous les titulaires
- identifiant unique (`id`)
- type de titulaire (`type` = 'PERSON' ou 'COMPANY')
- date de création
```sql
create table holder (
id bigint primary key generated always as identity,
type text not null check (type in ('PERSON', 'COMPANY')),
created_at timestamp not null default now()
);
```
`person` : informations propres aux personnes physiques
- prénom, nom, date de naissance
```sql
create table person (
id bigint primary key references holder(id) on delete cascade,
firstname text not null,
lastname text not null,
birthdate date not null
);
```
`company` : informations propres aux entreprises
- raison sociale, numéro dimmatriculation, date de création
```sql
create table company (
id bigint primary key references holder(id) on delete cascade,
name text not null,
registration_number text unique not null,
created_at date not null
);
```
### Tests d'insertion des données
```sql
-- Création dun titulaire de type personne physique
insert into holder(type) values ('PERSON') returning id;
-- Utilisons l'id qui est retourné (1)
insert into person(id, firstname, lastname, birthdate)
values (1, 'Françoise', 'Zanetti', '1995-04-12');
```
```sql
-- Création dun titulaire de type entreprise
insert into holder(type) values ('COMPANY') returning id;
-- Utilisons l'id qui est retourné (2)
insert into company(id, name, registration_number, created_at)
values (2, 'Boulangerie de Valorgue', 'FR19803269968', '2014-08-19');
```
### Vérification
```sql
select h.id, h.type, h.created_at,
p.firstname || ' ' || p.lastname as person,
c.name as company
from holder h
left join person p on p.id = h.id
left join company c on c.id = h.id
order by h.id;
```
#### 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 dinsérer une person sans holder ?
La clé étrangère references holder(id) dans person.
### 1.6 Contôle de l'âge
Contrainte déclarative
```sql
alter table person
add constraint chk_person_minimum_age
check (birthdate <= current_date - interval '15 years');
```
Contrainte procédurale avec un trigger :
```sql
create or replace function check_person_age()
returns trigger as $$
begin
if new.birthdate > current_date - interval '15 years' then
raise exception 'Holder must be at least 15 years old';
end if;
return new;
end;
$$ language plpgsql;
create trigger trg_check_person_age
before insert or update on person
for each row execute procedure check_person_age();
```

View File

@@ -1,7 +1,64 @@
# Travaux pratiques # Modélisation d'un système bancaire
Lobjectif est de modéliser et manipuler la base de données dun système bancaire simplifié, dans lequel : ## Objectifs
- Un compte bancaire (_account_) appartient à un ou plusieurs titulaires (_holders_). - Concevoir un **modèle relationnel** à partir dun scénario réaliste.
- Un titulaire peut être un individu (_person_) ou une société (_company_). - Utiliser les **contraintes dintégrité** pour garantir la cohérence des données.
- Manipuler des **jointures** et des **relations nn**.
- 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 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
- Un compte bancaire appartient à un ou plusieurs titulaires (_holders_).
- Chaque compte dispose dun numéro de compte (_account number_) unique et dun solde. - Chaque compte dispose dun numéro de compte (_account number_) unique et dun solde.

View File

@@ -469,10 +469,10 @@ END $$;
DROP table exchange; DROP table exchange;
-- ---------------------------------------------------------------------- -- ----------------------------------------------------------------------
-- Titulaires -- Titulaires (Holders)
-- ---------------------------------------------------------------------- -- ----------------------------------------------------------------------
CREATE TABLE bank.titulaire ( CREATE TABLE bank.holder (
id bigint primary key generated always as identity, id bigint primary key generated always as identity,
type_titulaire TEXT CHECK (type_titulaire IN ('individu', 'société')) NOT NULL, type_titulaire TEXT CHECK (type_titulaire IN ('individu', 'société')) NOT NULL,
created_at timestamp with time zone not null default now() created_at timestamp with time zone not null default now()
@@ -484,7 +484,7 @@ DECLARE
new_titulaire_id INTEGER; new_titulaire_id INTEGER;
BEGIN BEGIN
IF NEW.id IS NULL THEN IF NEW.id IS NULL THEN
INSERT INTO bank.titulaire (type_titulaire) VALUES ('individu') INSERT INTO bank.holder (type_titulaire) VALUES ('individu')
RETURNING id INTO new_titulaire_id; RETURNING id INTO new_titulaire_id;
NEW.id := new_titulaire_id; NEW.id := new_titulaire_id;
END IF; END IF;
@@ -503,7 +503,7 @@ DECLARE
new_titulaire_id INTEGER; new_titulaire_id INTEGER;
BEGIN BEGIN
IF NEW.id IS NULL THEN IF NEW.id IS NULL THEN
INSERT INTO bank.titulaire (type_titulaire) VALUES ('société') INSERT INTO bank.holder (type_titulaire) VALUES ('société')
RETURNING id INTO new_titulaire_id; RETURNING id INTO new_titulaire_id;
NEW.id := new_titulaire_id; NEW.id := new_titulaire_id;
END IF; END IF;
@@ -530,7 +530,7 @@ create table bank.account (
create table bank.account_holders ( create table bank.account_holders (
account_id bigint NOT NULL REFERENCES bank.account(id) ON DELETE CASCADE, account_id bigint NOT NULL REFERENCES bank.account(id) ON DELETE CASCADE,
titulaire_id int NOT NULL REFERENCES bank.titulaire(id) ON DELETE CASCADE, titulaire_id int NOT NULL REFERENCES bank.holder(id) ON DELETE CASCADE,
share numeric(5,2) CHECK (share >= 0 AND share <= 100), share numeric(5,2) CHECK (share >= 0 AND share <= 100),
role text DEFAULT 'Titulaire', role text DEFAULT 'Titulaire',
PRIMARY KEY (account_id, titulaire_id) PRIMARY KEY (account_id, titulaire_id)