Exercice 3 Asie – Bac NSI 2025 – Jour 2
Dans cette partie, on s'intéresse à la gestion de la base de données d'un hôpital.
mots clés: POO, BDD, SQL, arbres binaires
🔎 Voir les exercices similaires ↓
Asie – Bac NSI 2025 – Jour 2 Énoncé de l'exercice 3
Cet exercice porte sur la programmation Python (dictionnaire, récursivité, spécification), la programmation orientée objet, les bases de données relationnelles, les requêtes SQL et les arbres binaires.
Cet exercice est composé de 3 parties indépendantes.
Partie A
Dans cette partie, on s’intéresse à la gestion de la base de données d’un hôpital. On pourra utiliser les mots-clés SQL suivants : AND, FROM, INSERT, INTO, JOIN, ON, SELECT, SET, UPDATE, VALUES, WHERE. On utilisera également la fonction d’agrégation COUNT qui renvoie le nombre d’enregistrements correspondant à une requête.
La table Patient possède les attributs suivants :
nom_patient de type TEXT (clé primaire) ;
prenom de type TEXT ;
numero_secu de type INT ;
age de type INT.
| Patient | |||
|---|---|---|---|
| nom_patient | prenom | numero_secu | age |
| Heartman | Alice | 207053523800187 | 17 |
| Douglas | Bob | 100017500155572 | 24 |
| Woods | Caroll | 258125930610747 | 65 |
La table Symptome possède les attributs suivants :
nom_patient de type TEXT (clé primaire et clé étrangère) ;
toux de type TEXT ;
fievre de type TEXT ;
nausee de type TEXT ;
anosmie de type TEXT.
| Symptome | ||||
|---|---|---|---|---|
| nom_patient | toux | fievre | nausee | anosmie |
| Heartman | Oui | Non | Non | Oui |
| Douglas | Non | Oui | Oui | Non |
| Woods | Oui | Oui | Non | Non |
La table Maladie possède, entre autres, l’attribut nom_maladie de type TEXT, qui est la clé primaire. Les autres attributs de cette table ne sont pas représentés car ils ne sont pas utiles pour l’exercice.
| Maladie |
|---|
| nom_maladie |
| Covid-19 |
| Gastroentérite |
La table Diagnostic possède les attributs suivants :
nom_patient de type TEXT (clé primaire et clé étrangère) ;
nom_maladie de type TEXT (clé étrangère).
| Diagnostic | |
|---|---|
| nom_patient | nom_maladie |
| …….. …….. …….. | …….. …….. …….. |
Écrire une requête SQL permettant d’obtenir les noms et prénoms des patients ayant strictement plus de 60 ans.
Alice Heartman ne tousse plus. Écrire une requête SQL permettant de mettre à jour la base de données avec cette information.
On souhaite effectuer des statistiques sur les symptômes des patients atteints de Covid-19. Écrire une requête SQL permettant de connaître le nombre de patients avec un diagnostic de Covid-19 qui toussent.
Un employé de l’hôpital saisit la requête suivante :
INSERT INTO Patients VALUES ('Douglas', 'Patrick', 168077230253829, 55)
Expliquer pourquoi cette requête produit une erreur.
Proposer une modification du schéma relationnel qui permettrait de résoudre ce problème.
Partie B
On s’intéresse maintenant à l’automatisation du diagnostic à partir des symptômes. Cette automatisation se fait à l’aide d’un arbre de décision binaire, tel que celui illustré sur la figure 1.

Chaque nœud interne de l’arbre est étiqueté par un symptôme, et chaque feuille est étiquetée par un diagnostic. Pour établir un diagnostic, on se place à la racine et on parcourt l’arbre de la manière suivante :
si on arrive à une feuille, le diagnostic est l’étiquette de cette feuille ;
sinon, on regarde si l’étiquette du nœud est un des symptômes du patient. Si oui, on continue le parcours dans le sous-arbre droit, sinon, on continue le parcours dans le sous-arbre gauche.
L’arbre de la figure 1 donne un diagnostic pour la Covid-19. Par exemple, un patient qui ne tousse pas et n’a pas d’anosmie, mais a de la fièvre et des nausées est diagnostiqué négatif si on suit cet arbre de décision.
Donner le diagnostic pour un patient qui tousse et qui a de la fièvre, mais n’a pas de nausée ni d’anosmie, d’après l’arbre de la figure 1.
On décide d’implémenter les arbres binaires à l’aide de la classe Noeud ci-dessous :
class Noeud:
def __init__(self, valeur, gauche = None, droit = None):
"""valeur correspond au symptome si le noeud est
interne ou au diagnostic si le noeud est une feuille"""
self.valeur = valeur
self.gauche = gauche
self.droit = droit
def est_feuille(self):
"""renvoie vrai si le noeud est une feuille faux sinon"""
return self.gauche == None and self.droit == None
def symptome(self):
assert not self.est_feuille()
return self.valeur
def diagnostic(self):
assert self.est_feuille()
return self.valeur
Préciser la signification de l’assertion de la méthode symptome.
Nommer un attribut et une méthode de la classe Noeud.
On représente les symptômes d’un patient en Python par un dictionnaire dont les clés sont les symptômes possibles, et les valeurs sont True si le patient présente ce symptôme et False sinon.
Par exemple, les symptômes du patient de la question 6 sont représentés par le dictionnaire suivant :
patient = {'toux': True, 'fievre': True, 'nausee': False, 'anosmie': False}
Compléter la fonction applique suivante, définie récursivement, qui renvoie le diagnostic établi en utilisant un arbre de décision binaire implémenté à l’aide de la classe Noeud précédente.
def applique(arbre, patient):
if arbre.est_feuille():
...
else:
if patient[arbre.symptome()]:
...
else:
...
Donner la taille de l’arbre représenté en figure 1. On considère que la taille d’un arbre constitué d’une unique feuille est 1.
On souhaite réduire la taille de cet arbre en utilisant l’observation suivante : un nœud dont les deux sous-arbres sont des feuilles correspondant au même diagnostic peut être remplacé par une feuille correspondant à ce diagnostic, comme illustré en figure 2.

Appliquer cette règle à l’arbre de la figure 1 pour le réduire et dessiner le nouvel arbre.
Compléter la méthode reduire qui permet d’appliquer cette règle récursivement pour réduire la taille d’un arbre de décision binaire.
def reduire(self): # ligne 1
"""fonction récursive qui réduit la taille d'un arbre de
décision sans changer les décisions prises"""
if self.est_feuille(): # ligne 4
return
self.gauche.reduire() # ligne 6
self. ... # ligne 7
if self.gauche.est_feuille() and ... \
and ... == ... : # ligne 9
self.valeur = ... # ligne 10
self.gauche = ... # ligne 11
self.droite = ... # ligne 12
Partie C
Dans cette partie, on s’intéresse à l’intégrité et à la sécurité des données.
Sur les 15 chiffres du numéro de sécurité sociale, 2 servent à détecter les erreurs : étant donné le nombre n formé des 13 premiers chiffres, le nombre k formé des 2 derniers chiffres, appelé la clé, est choisi pour que n+k soit un multiple de 97.
Par exemple, 207053523800187 est bien formé car :
2070535238001 + 87 = 97 x 21345724104.
On rappelle que les opérateurs % et // permettent en Python d’obtenir respectivement le reste et le quotient dans une division euclidienne. Par exemple : 13 % 3 renvoie 1 et 13//3 renvoie 4 (car 13=3×4+1). On peut donc vérifier qu’un nombre entier 𝑛 est un multiple de 𝑝 en testant si le reste de la division de 𝑛 par 𝑝 vaut zéro.
Recopier et compléter la fonction verifie suivante qui renvoie un booléen indiquant si un numéro de sécurité sociale représenté par un entier (type int) est bien formé.
def verifie(num_secu):
n = num_secu // 100
k = num_secu % 100
return ...
Compléter la fonction cle qui permet de renvoyer la clé k d’un numéro de sécurité sociale en prenant pour paramètre le nombre n formé des 13 premiers chiffres du numéro de sécurité sociale.
def cle(n):
...
Asie – Bac NSI 2025 – Jour 2 Correction de l'exercice 3
PARTIE A — Base de données (SQL)
1) Patients de plus de 60 ans
SELECT nom_patient, prenom
FROM Patient
WHERE age > 60;
2) Mise à jour : Alice Heartman ne tousse plus
UPDATE Symptome
SET toux = 'Non'
WHERE nom_patient = 'Heartman';
3) Nombre de patients Covid-19 qui toussent
SELECT COUNT(*)
FROM Diagnostic
JOIN Symptome
ON Diagnostic.nom_patient = Symptome.nom_patient
WHERE nom_maladie = 'Covid-19'
AND toux = 'Oui';
4) Pourquoi la requête INSERT produit une erreur?
INSERT INTO Patients VALUES ('Douglas', 'Patrick', 168077230253829, 55)
Erreur car :
La table s’appelle Patient (et non Patients)
nom_patient est clé primaire
Douglas existe déjà
Il y a violation de la contrainte d’unicité.
5) Modification du schéma relationnel
Problème : plusieurs patients peuvent avoir le même nom.
Solution : ajouter un identifiant unique : id_patient INT PRIMARY KEY
Et faire de nom_patient un simple attribut.
Il faut alors remplacer nom_patient par id_patient dans les tables Symptome et Diagnostic, où il sert de clé étrangère (et de clé primaire).
Bonne pratique : ne jamais utiliser un nom comme clé primaire.
PARTIE B — Arbre de décision
6) Diagnostic du patient
Patient :
toux = True
fievre = True
nausee = False
anosmie = False
On suit l’arbre de la figure 1 : toux Oui → fievre Oui → nausee Non → anosmie Non : on arrive sur une feuille « + ».
Diagnostic : positif à la Covid-19.
7) Assertion de la méthode symptome
L’assertion vérifie que le nœud n’est pas une feuille.
Elle garantit qu’on appelle la méthode uniquement sur un nœud interne.
8) Un attribut et une méthode
Attribut : valeur (ou gauche, droit)
Méthode : est_feuille (ou symptome, diagnostic)
9) Fonction applique (récursive)
def applique(arbre, patient):
if arbre.est_feuille():
return arbre.diagnostic()
else:
if patient[arbre.symptome()]:
return applique(arbre.droit, patient) # symptôme : à droite
else:
return applique(arbre.gauche, patient)
10) Taille de l’arbre
L’arbre de la figure 1 est complet : 1 + 2 + 4 + 8 = 15 nœuds internes et 16 feuilles.
Taille = 15 + 16 = 31
11) Réduction de l’arbre
On applique la règle :
Si un nœud a deux feuilles identiques → on le remplace par une feuille.
Les nœuds anosmie dont les deux feuilles sont identiques deviennent des feuilles (6 nœuds sur 8). On réapplique la règle : le nœud nausee de la branche toux Oui, fievre Oui a alors deux feuilles « + » et devient lui aussi une feuille. Plus rien ne se simplifie ensuite.

L’arbre réduit a 8 nœuds internes et 9 feuilles : sa taille passe de 31 à 17.
12) Méthode reduire
def reduire(self):
"""fonction récursive qui réduit la taille d'un arbre de
décision sans changer les décisions prises"""
if self.est_feuille():
return
self.gauche.reduire()
self.droit.reduire()
if self.gauche.est_feuille() and self.droit.est_feuille() \
and self.gauche.valeur == self.droit.valeur:
self.valeur = self.gauche.valeur
self.gauche = None
self.droit = None
PARTIE C — Intégrité des données
13) Fonction verifie
def verifie(num_secu):
n = num_secu // 100
k = num_secu % 100
return (n + k) % 97 == 0
14) Fonction cle
On veut : n + k ≡ 0 mod 97
Donc :
Il suffit de compléter n jusqu’au multiple de 97 suivant : k = 97 − (n % 97).
def cle(n):
reste = n % 97
if reste == 0:
return 0
return 97 - reste
Une erreur, un oubli ? Écrivez-moi : frederic.peuriere@lfcl.pt
🔎 Exercices sur des thèmes similaires
-
Asie 2024 – jour 1 – exercice 3
programmation, POO, BDD, SQL — Difficulté : 🔥🔥🔥🔥🔥 -
Centres étrangers 2024 – jour 1 – exercice 3
programmation, POO, BDD, SQL — Difficulté : 🔥🔥🔥🔥🔥 -
Polynésie 2025 – jour 2 – exercice 2
programmation, POO, BDD, SQL — Difficulté : 🔥🔥🔥🔥🔥 -
Nouvelle Calédonie 2025 – jour 1 – exercice 2
BDD, SQL , POO — Difficulté : 🔥🔥🔥🔥🔥 -
Centres étrangers 2026 – jour 1 – exercice 3
POO, récursivité, BDD, SQL — Difficulté : 🔥🔥🔥🔥🔥 -
Sujet Zéro 2024 – jour 2 – exercice 3
dictionnaires, POO, BDD, SQL — Difficulté : 🔥🔥🔥🔥🔥