Relier les tables : JOIN
Pourquoi plusieurs tables ?
Dans la table ventes, le nom Paul est écrit 17 fois et riz 15 fois. Que se passe-t-il si :
- Paul change de numéro de téléphone ? Il faudrait l'écrire dans chaque vente ;
- le prix du riz change ? Les anciennes ventes doivent garder l'ancien prix, les nouvelles le nouveau ;
- quelqu'un tape
Pualune fois ? Les totaux de Paul deviennent faux sans que personne ne le voie.
La solution des bases relationnelles : une table par sujet, reliées par des numéros.
produits vendeurs
id | nom | prix_achat | ... id | nom | telephone
1 | riz | 1000 | 1 | Awa | 690112233
2 | huile | 1250 | 2 | Paul | 677445566
ventes
id | date | produit_id | vendeur_id | quantite
1 | 2026-01-01 | 1 | 1 | 5
2 | 2026-01-02 | 2 | 2 | 10
La vente n°2 ne dit plus « huile, Paul » : elle dit « produit 2, vendeur 2 ». Le nom de Paul n'est écrit qu'une seule fois, dans la table vendeurs.
La nouvelle base, boutique2.sql, a aussi deux informations qu'on n'avait pas : le prix d'achat de chaque produit, qui permet enfin de calculer le bénéfice, et un nouveau vendeur, Junior, embauché il y a peu.
JOIN : recoller les morceaux
SELECT ventes.date, produits.nom, ventes.quantite
FROM ventes
JOIN produits ON ventes.produit_id = produits.id;
Lis-le ainsi : « pour chaque vente, va chercher la ligne de produits dont l'id est égal au produit_id de la vente, et colle-les ensemble ».
Quand deux tables ont des colonnes du même nom (id, nom), on précise la table : produits.nom, vendeurs.nom. Pour écrire moins, on donne un alias court à chaque table :
SELECT v.date, p.nom, d.nom
FROM ventes v
JOIN produits p ON v.produit_id = p.id
JOIN vendeurs d ON v.vendeur_id = d.id;
On peut enchaîner autant de JOIN que nécessaire.
Le bénéfice
SELECT p.nom, SUM(v.quantite * (p.prix_vente - p.prix_achat)) AS benefice
FROM ventes v
JOIN produits p ON v.produit_id = p.id
GROUP BY p.nom
ORDER BY benefice DESC;
Exercice : Recoller ventes, produits et vendeurs
Dans boutique2.sql, écris une requête qui donne, pour les 3 premières ventes (dans l'ordre de leur id), la date, le nom du produit et le nom du vendeur.
Voir une solution
import sqlite3
conn = sqlite3.connect(":memory:")
conn.executescript(open("boutique2.sql", encoding="utf-8").read())
requete = """
SELECT v.date, p.nom, d.nom
FROM ventes v
JOIN produits p ON v.produit_id = p.id
JOIN vendeurs d ON v.vendeur_id = d.id
ORDER BY v.id
LIMIT 3
"""
resultat = conn.execute(requete).fetchall()
for ligne in resultat:
print(ligne)Dans l'appli, ton code est exécuté et corrigé automatiquement. Faire l'exercice
Exercice : Ce que chaque produit rapporte vraiment
Écris une requête qui donne, pour chaque produit vendu, son nom et son bénéfice total (quantité x marge), du plus rentable au moins rentable.
Voir une solution
import sqlite3
conn = sqlite3.connect(":memory:")
conn.executescript(open("boutique2.sql", encoding="utf-8").read())
requete = """
SELECT p.nom, SUM(v.quantite * (p.prix_vente - p.prix_achat)) AS benefice
FROM ventes v
JOIN produits p ON v.produit_id = p.id
GROUP BY p.nom
ORDER BY benefice DESC
"""
resultat = conn.execute(requete).fetchall()
for ligne in resultat:
print(ligne)Dans l'appli, ton code est exécuté et corrigé automatiquement. Faire l'exercice
LEFT JOIN : ce qui n'a pas de correspondance
Junior n'a encore rien vendu. Et le sel est dans le catalogue, mais personne n'en a acheté. Avec un JOIN ordinaire, ils disparaissent du résultat : il n'y a aucune vente à coller à côté d'eux.
SELECT d.nom, v.id
FROM vendeurs d
LEFT JOIN ventes v ON v.vendeur_id = d.id
WHERE v.id IS NULL;
« Tous les vendeurs, avec leurs ventes s'ils en ont ; garde ceux qui n'en ont aucune. » Résultat : Junior. C'est la requête classique pour trouver les clients inactifs, les produits invendus, les élèves sans note.
Exercice : Les produits jamais vendus
Écris une requête qui donne le nom des produits du catalogue qui n'ont jamais été vendus.
Voir une solution
import sqlite3
conn = sqlite3.connect(":memory:")
conn.executescript(open("boutique2.sql", encoding="utf-8").read())
requete = """
SELECT p.nom
FROM produits p
LEFT JOIN ventes v ON v.produit_id = p.id
WHERE v.id IS NULL
"""
resultat = conn.execute(requete).fetchall()
for ligne in resultat:
print(ligne)Dans l'appli, ton code est exécuté et corrigé automatiquement. Faire l'exercice