Une base de données n'existe pas pour être consultée à la main : elle sert à des programmes. Tu ouvres la base depuis Python, tu lui envoies une requête SELECT et tu utilises les lignes obtenues.
Dans DB Browser, c'est toi qui écris la requête et qui lis le résultat. Dans une vraie application — un site web, un logiciel de gestion, une appli de téléphone — personne n'ouvre DB Browser : c'est un programme qui envoie les requêtes et utilise les réponses. Dans cet article, ce programme, c'est toi qui l'écris, en Python.
💡 Télécharge
mon-ecole-eleves.dbdans la sidebar, renomme-lamon-ecole.dbet place-la dans le même dossier que tes fichiers Python. La base contient une tableelevede douze élèves, avec les colonnesid,nom,prenom,date_naissance,commune,absences.
À la fin de cet article, tu seras capable de :
SELECT et parcourir les lignes obtenues.NULL dans un programme.Python contient un module prévu pour SQLite. Il fait partie de Python lui-même : il n'y a rien à installer.
import sqlite3
Rappel sur le langage SQL : une requête SELECT colonnes FROM table demande à la base d'afficher certaines colonnes d'une table. C'est exactement ce que ton programme va envoyer.
avant maintenant
DB Browser programme Python
│ │
│ SELECT ... FROM ... │ SELECT ... FROM ...
▼ ▼
mon-ecole.db
Crée un fichier eleves.py dans le dossier de la base, et écris :
import sqlite3
conn = sqlite3.connect("mon-ecole.db")
curseur = conn.execute("SELECT nom, prenom FROM eleve")
for ligne in curseur:
print(ligne)
conn.close()
Exécute-le. Tu obtiens :
('Adam', 'Lucas')
('Bastin', 'Emma')
('Charlier', 'Noah')
('Delvaux', 'Léa')
('Englebert', 'Hugo')
('Fontaine', 'Chloé')
('Gérard', 'Nathan')
('Hubert', 'Manon')
('Istas', 'Louis')
('Jacques', 'Camille')
('Kevers', 'Arthur')
('Lambert', 'Sarah')
Regarde le texte entre guillemets : "SELECT nom, prenom FROM eleve". C'est une requête SQL tout à fait ordinaire, rangée dans une chaîne de caractères Python.
🧠 Python ne remplace pas SQL. Python transporte la requête jusqu'à SQLite, puis récupère la réponse pour en faire quelque chose.
Tout programme qui utilise une base suit trois étapes.
conn = sqlite3.connect("mon-ecole.db") # 1. ouvrir la base
# ... 2. envoyer des requêtes ...
conn.close() # 3. refermer la base
📖 Nouvelle notion : la connexion
Une connexion est le lien ouvert entre un programme et une base de données. Toutes les requêtes passent par elle. On l'ouvre au début avec
sqlite3.connect(), et on la referme à la fin avecclose().En anglais : 🇬🇧 connection ; connect veut dire « connecter » et close « fermer ».
⚠️
sqlite3.connect()crée le fichier s'il n'existe pas. Si tu écrissqlite3.connect("mon_ecol.db")par erreur, Python ne dit rien : il crée une base vide. L'erreur n'apparaît qu'à la requête suivante :sqlite3.OperationalError: no such table: eleveQuand une table « disparaît », vérifie d'abord le nom du fichier et le dossier dans lequel ton programme s'exécute.
curseur = conn.execute("SELECT nom, prenom FROM eleve")
execute veut dire « exécuter ». Cette ligne envoie la requête à SQLite et range la réponse dans la variable curseur.
📖 Nouvelle notion : le curseur
Un curseur est un objet qui donne accès aux lignes du résultat d'une requête, une par une, comme un doigt qui avance dans une liste. On le parcourt avec une boucle
for.En anglais : 🇬🇧 cursor.
À chaque tour de la boucle for, la variable ligne contient la ligne suivante du résultat.
Chaque ligne s'affiche entre parenthèses : ('Adam', 'Lucas'). C'est un tuple, une suite de valeurs qu'on ne peut pas modifier. Comme dans une liste, on accède à chaque valeur par sa position, en commençant à 0.
for ligne in curseur:
print(ligne[1], ligne[0])
Lucas Adam
Emma Bastin
Noah Charlier
...
⚠️ Les positions suivent l'ordre des colonnes dans le
SELECT. AvecSELECT nom, prenom,ligne[0]est le nom. AvecSELECT prenom, nom,ligne[0]devient le prénom. Change la requête sans changer le programme, et tout s'inverse.
La boucle for n'est pas la seule façon de lire un curseur.
fetchone() (« aller chercher une ») renvoie la ligne suivante du résultat :
curseur = conn.execute("SELECT nom, prenom, commune FROM eleve")
print(curseur.fetchone())
print(curseur.fetchone())
('Adam', 'Lucas', 'Jodoigne')
('Bastin', 'Emma', 'Wavre')
Le curseur avance à chaque appel. Quand il n'y a plus de ligne, fetchone() renvoie None.
fetchall() (« aller chercher toutes ») renvoie une liste qui contient toutes les lignes :
lignes = conn.execute("SELECT prenom FROM eleve").fetchall()
print(lignes)
print(len(lignes))
[('Lucas',), ('Emma',), ('Noah',), ('Léa',), ('Hugo',), ('Chloé',), ('Nathan',), ('Manon',), ('Louis',), ('Camille',), ('Arthur',), ('Sarah',)]
12
Avec une liste, tu peux utiliser tout ce que Python sait faire : len() compte les éléments, lignes[0] donne la première ligne…
💡 Pourquoi
('Lucas',)avec une virgule ? La requête ne demande qu'une colonne, mais chaque résultat reste une ligne, donc un tuple. En Python, un tuple d'une seule valeur s'écrit avec une virgule. Pour obtenir la valeur seule, écrisligne[0].
| Méthode | Ce qu'elle renvoie | Quand l'utiliser |
|---|---|---|
for ligne in curseur |
une ligne à chaque tour | traiter les lignes une par une |
fetchone() |
la ligne suivante, ou None |
quand une seule ligne t'intéresse |
fetchall() |
une liste de toutes les lignes | compter les lignes ou les réutiliser |
ligne[1] ne dit pas ce qu'il contient. Python peut te donner des lignes où chaque valeur se lit par le nom de sa colonne. Il suffit d'une ligne juste après la connexion :
conn.row_factory = sqlite3.Row
Le programme devient :
import sqlite3
conn = sqlite3.connect("mon-ecole.db")
conn.row_factory = sqlite3.Row
curseur = conn.execute("SELECT prenom, nom, email FROM eleve")
for ligne in curseur:
print(ligne["prenom"], ligne["nom"], "-", ligne["email"])
conn.close()
ligne["prenom"] se lit tout seul, et le programme continue de fonctionner même si tu changes l'ordre des colonnes dans le SELECT.
💡 À partir de maintenant, ajoute toujours
conn.row_factory = sqlite3.Rowaprès la connexion.
Trois élèves n'ont pas d'adresse e-mail. Dans la base, leur case contient NULL, c'est-à-dire aucune valeur. Python le traduit par sa propre valeur « rien » : None.
for ligne in conn.execute("SELECT prenom, email FROM eleve"):
print(ligne)
...
('Noah', None)
...
Un programme bien écrit prévoit ce cas :
for ligne in curseur:
if ligne["email"] is None:
print(ligne["prenom"], ligne["nom"], "- pas d'adresse e-mail")
else:
print(ligne["prenom"], ligne["nom"], "-", ligne["email"])
Lucas Adam - lucas.adam@ecole.be
Emma Bastin - emma.bastin@ecole.be
Noah Charlier - pas d'adresse e-mail
Léa Delvaux - lea.delvaux@ecole.be
Hugo Englebert - hugo.englebert@ecole.be
Chloé Fontaine - pas d'adresse e-mail
Nathan Gérard - nathan.gerard@ecole.be
Manon Hubert - manon.hubert@ecole.be
Louis Istas - louis.istas@ecole.be
Camille Jacques - pas d'adresse e-mail
Arthur Kevers - arthur.kevers@ecole.be
Sarah Lambert - sarah.lambert@ecole.be
🧠
NULLdans la base devientNonedans Python. On le teste avecis None.
Un programme utile demande souvent quelque chose à l'utilisateur : « quelle commune veux-tu afficher ? ». Il faut alors une requête qui ne garde que certaines lignes.
Pour ça, SQL possède le mot-clé WHERE (« où »). SELECT prenom, nom FROM eleve WHERE commune = 'Wavre' affiche uniquement les élèves dont la commune vaut Wavre.
La valeur vient de l'utilisateur. On place un point d'interrogation dans la requête, et on donne la valeur à part :
import sqlite3
conn = sqlite3.connect("mon-ecole.db")
conn.row_factory = sqlite3.Row
commune = input("Commune : ")
curseur = conn.execute(
"SELECT prenom, nom FROM eleve WHERE commune = ?",
(commune,)
)
lignes = curseur.fetchall()
if len(lignes) == 0:
print("Aucun élève n'habite à", commune)
else:
print(len(lignes), "élève(s) trouvé(s) :")
for ligne in lignes:
print("-", ligne["prenom"], ligne["nom"])
conn.close()
Commune : Wavre
2 élève(s) trouvé(s) :
- Emma Bastin
- Nathan Gérard
Commune : Bruxelles
Aucun élève n'habite à Bruxelles
📖 Nouvelle notion : la requête paramétrée
Une requête paramétrée contient un
?à l'endroit où une valeur doit être placée. La valeur est transmise séparément, dans un tuple. SQLite place lui-même la valeur au bon endroit, sans jamais la confondre avec du SQL.En anglais : 🇬🇧 parameterized query.
⚠️ Ne fabrique jamais une requête en collant du texte. Écrire
"... WHERE commune = '" + commune + "'"semble plus simple, mais un utilisateur malveillant pourrait taper du SQL à la place d'un nom de commune et faire exécuter ce qu'il veut à ta base. Cette attaque s'appelle une injection SQL. Le?l'empêche.
💡 La petite virgule de
(commune,). En Python,(commune)est une simple variable entre parenthèses. Pour créer un tuple d'une seule valeur, il faut la virgule :(commune,).
Tous les programmes ouvrent mon-ecole.db et la referment à la fin.
Écris un programme qui affiche tous les élèves sous la forme Lucas ADAM, avec le nom en majuscules. Utilise row_factory et lis les colonnes par leur nom.
💡 En Python,
"Adam".upper()donne"ADAM".
Écris un programme qui :
fetchall() et len() ;fetchone().Exécute ce programme, sans row_factory :
import sqlite3
conn = sqlite3.connect("mon-ecole.db")
for ligne in conn.execute("SELECT prenom, absences FROM eleve"):
print(ligne)
conn.close()
Lucas : 2 demi-jour(s), avec ligne[0] et ligne[1].SELECT sans toucher au print. Que se passe-t-il ?row_factory et réécris le print avec les noms de colonnes. Échange à nouveau les colonnes : que constates-tu ?Écris un programme qui parcourt tous les élèves et affiche uniquement ceux qui n'ont pas d'adresse e-mail, puis leur nombre total.
Élèves sans adresse e-mail :
- Noah Charlier
- Chloé Fontaine
- Camille Jacques
Total : 3
Fais le tri en Python, avec is None.
Reprends le programme de recherche par commune.
Jodoigne. Combien d'élèves obtiens-tu ?Écris un programme qui affiche en boucle :
1. Lister tous les élèves
2. Chercher les élèves d'une commune
3. Afficher les élèves sans adresse e-mail
4. Quitter
La connexion est ouverte une seule fois, avant la boucle, et refermée quand l'utilisateur quitte. Pour le choix 2, la commune est transmise avec un ?.
sqlite3 fait partie de Python : import sqlite3, rien à installer.sqlite3.connect(), envoie ses requêtes avec execute(), puis la referme avec close().for, fetchone() pour une ligne, fetchall() pour la liste complète.conn.row_factory = sqlite3.Row, on lit ses valeurs par le nom des colonnes.NULL dans la base devient None dans Python.? et un tuple, jamais par une chaîne collée : c'est la protection contre l'injection SQL.Tu as fait le tour d'une entité : la découvrir, la ranger dans une table, l'identifier et la lire, à la main comme depuis un programme. Révise l'essentiel avec la fiche à étudier, puis passe au niveau Filtrer et analyser ses données pour poser des questions beaucoup plus précises.