Le problème : une base n'est pas figée
Lire des données, c'est 80 % du travail. Mais il faut bien que ces données arrivent quelque part : un nouveau client s'inscrit, change d'email, supprime son compte. Trois actions, trois commandes : INSERT, UPDATE, DELETE.
Ce sont les commandes les plus dangereuses du SQL. Une erreur de lecture renvoie un mauvais résultat ; une erreur d'écriture détruit des données réelles. On reste sur la table clients.
INSERT INTO : ajouter une ligne
INSERT INTO crée une nouvelle ligne. On nomme les colonnes, puis on donne les valeurs dans le même ordre :
INSERT INTO clients (nom, email, ville)
VALUES ('Léa Martin', 'lea@exemple.fr', 'Lyon');
On ne fournit pas l'id : il est auto-incrémenté par la base. On peut insérer plusieurs lignes d'un coup :
INSERT INTO clients (nom, email, ville)
VALUES
('Karim Benali', 'karim@exemple.fr', 'Dijon'),
('Marie Dupont', 'marie@exemple.fr', 'Besançon');
Nommer explicitement les colonnes (INSERT INTO clients (nom, email, ville)) est plus sûr que de compter sur l'ordre des colonnes de la table : si la structure change un jour, votre requête continue de fonctionner.
UPDATE et DELETE : le WHERE est vital
UPDATE modifie des lignes existantes. DELETE en supprime. Les deux doivent être accompagnés d'un WHERE qui désigne précisément les lignes visées :
Une table clients contient 5 000 lignes. Un développeur voulait désactiver un seul client et lance UPDATE clients SET actif = 0 sans clause WHERE. Avant de dérouler : combien de lignes sont modifiées ? Et que fait DELETE FROM clients sans WHERE sur cette même table ?
Voir la réponse
UPDATE clients SET actif = 0 sans WHERE modifie les 5 000 lignes : sans condition, l'opération s'applique à toute la table. De même, DELETE FROM clients sans WHERE supprime toutes les lignes et vide la table. C'est la catastrophe classique : un WHERE oublié sur un UPDATE ou un DELETE écrase ou efface toute la base, sans confirmation. Réflexes de survie : toujours écrire le WHERE avant le reste, tester d'abord la condition avec un SELECT ... WHERE ... pour voir les lignes visées, et travailler dans une transaction (BEGIN ... ROLLBACK/COMMIT) quand c'est possible.
UPDATE clients
SET email = 'nouveau@exemple.fr'
WHERE id = 1;
DELETE FROM clients
WHERE id = 1;
Le WHERE id = 1 garantit qu'on ne touche qu'une seule ligne, celle de l'utilisateur concerné.
La catastrophe du WHERE oublié
Voici l'erreur qui a déjà coûté leur week-end à des milliers de développeurs :
-- CATASTROPHE : pas de WHERE
UPDATE clients SET email = 'test@test.fr'; -- réécrit l'email de TOUS les clients
DELETE FROM clients; -- vide la table ENTIÈRE
Un UPDATE ou un DELETE sans WHERE s'applique à TOUTE la table. Pas une ligne : toutes. Vos 50 000 clients voient leur email réécrit, ou disparaissent d'un coup. Réflexe de survie : écrivez toujours le WHERE AVANT le reste, et testez d'abord avec un SELECT portant le même WHERE pour voir quelles lignes seront touchées.
Filet de sécurité supplémentaire : la transaction. BEGIN ouvre une zone de travail, COMMIT valide les changements, ROLLBACK annule tout si quelque chose a mal tourné, comme un Ctrl+Z sur la base.
BEGIN;
DELETE FROM clients WHERE id = 1;
-- on vérifie le résultat... puis :
COMMIT; -- ou ROLLBACK; pour tout annuler
Les transactions : tout ou rien
On a entr'aperçu BEGIN et ROLLBACK comme filet de sécurité pour un DELETE risqué. Mais les transactions ont une vocation plus profonde : garantir qu'un ensemble d'opérations réussit en bloc ou n'a jamais eu lieu.
Imaginez un virement bancaire. Deux étapes sont nécessaires : débiter le compte A de 30 euros, puis créditer le compte B de 30 euros. Si le serveur tombe entre les deux, vous avez débité sans créditer : 30 euros ont disparu. C'est exactement le genre de désastre qu'une transaction empêche.
Une transaction regroupe plusieurs instructions en un bloc atomique : soit toutes réussissent et deviennent définitives d'un coup (COMMIT), soit une échoue et tout est annulé comme si rien ne s'était passé (ROLLBACK). La base revient exactement à l'état d'avant le BEGIN.
Rollback : le filet de sécurité. Si on détecte un problème en cours de route, ROLLBACK efface tout proprement :
-- Démonstration ROLLBACK : le solde d'Alice ne change pas
CREATE TABLE comptes (id INTEGER, nom TEXT, solde INTEGER);
INSERT INTO comptes VALUES (1, 'Alice', 100);
INSERT INTO comptes VALUES (2, 'Bob', 50);
BEGIN;
UPDATE comptes SET solde = solde - 30 WHERE id = 1;
ROLLBACK;
SELECT nom, solde FROM comptes;
Alice reste à 100 : le débit a été annulé intégralement.
Commit : valider un virement complet. Quand les deux étapes réussissent, COMMIT les rend définitives ensemble :
-- Démonstration COMMIT : débit + crédit validés en bloc
CREATE TABLE comptes (id INTEGER, nom TEXT, solde INTEGER);
INSERT INTO comptes VALUES (1, 'Alice', 100);
INSERT INTO comptes VALUES (2, 'Bob', 50);
BEGIN;
UPDATE comptes SET solde = solde - 30 WHERE id = 1;
UPDATE comptes SET solde = solde + 30 WHERE id = 2;
COMMIT;
SELECT nom, solde FROM comptes;
Alice passe à 70, Bob à 80 : les 30 euros ont bien transité, aucune étape n'a été laissée à moitié.
Règle d'or : toute opération critique en plusieurs étapes mérite une transaction. Encadrez-la avec BEGIN au départ et COMMIT à la fin. Si une étape échoue ou donne un résultat inattendu, lancez ROLLBACK : la base revient à son état initial, proprement, sans données à moitié modifiées. C'est le standard pour les virements, commandes, mises à jour liées entre plusieurs tables.
The problem: a database is not frozen
Reading data is 80% of the job. But that data has to arrive somewhere: a new customer signs up, changes their email, deletes their account. Three actions, three commands: INSERT, UPDATE, DELETE.
These are the most dangerous SQL commands. A read error returns a wrong result; a write error destroys real data. We stay on the clients table.
INSERT INTO: add a row
INSERT INTO creates a new row. You name the columns, then give the values in the same order:
INSERT INTO clients (nom, email, ville)
VALUES ('Lea Martin', 'lea@exemple.fr', 'Lyon');
You do not provide the id: it is auto-incremented by the database. You can insert several rows at once:
INSERT INTO clients (nom, email, ville)
VALUES
('Karim Benali', 'karim@exemple.fr', 'Dijon'),
('Marie Dupont', 'marie@exemple.fr', 'Besancon');
Explicitly naming the columns (INSERT INTO clients (nom, email, ville)) is safer than relying on the table's column order: if the structure changes one day, your query keeps working.
UPDATE and DELETE: the WHERE is vital
UPDATE modifies existing rows. DELETE removes them. Both must come with a WHERE that precisely targets the rows:
A clients table holds 5,000 rows. A developer wanted to deactivate a single customer and runs UPDATE clients SET actif = 0 without a WHERE clause. Before scrolling down: how many rows are modified? And what does DELETE FROM clients without WHERE do on that same table?
See the answer
UPDATE clients SET actif = 0 without WHERE modifies all 5,000 rows: without a condition, the operation applies to the whole table. Likewise, DELETE FROM clients without WHERE deletes every row and empties the table. This is the classic catastrophe: a forgotten WHERE on an UPDATE or DELETE overwrites or erases the entire dataset with no confirmation. Survival reflexes: always write the WHERE before anything else, test the condition first with a SELECT ... WHERE ... to see which rows are targeted, and work inside a transaction (BEGIN ... ROLLBACK/COMMIT) whenever possible.
UPDATE clients
SET email = 'nouveau@exemple.fr'
WHERE id = 1;
DELETE FROM clients
WHERE id = 1;
The WHERE id = 1 guarantees we touch a single row, the one of the relevant user.
The catastrophe of the forgotten WHERE
Here is the mistake that has already cost thousands of developers their weekend:
-- CATASTROPHE: no WHERE
UPDATE clients SET email = 'test@test.fr'; -- rewrites EVERY customer's email
DELETE FROM clients; -- wipes the WHOLE table
An UPDATE or DELETE without WHERE applies to the WHOLE table. Not one row: all of them. Your 50,000 customers get their email rewritten, or vanish at once. Survival reflex: always write the WHERE BEFORE the rest, and test first with a SELECT using the same WHERE to see which rows will be affected.
An extra safety net: the transaction. BEGIN opens a workspace, COMMIT validates the changes, ROLLBACK cancels everything if something went wrong — like a Ctrl+Z on the database.
BEGIN;
DELETE FROM clients WHERE id = 1;
-- check the result... then:
COMMIT; -- or ROLLBACK; to cancel everything
Transactions: all or nothing
We caught a glimpse of BEGIN and ROLLBACK earlier as a safety net for a risky DELETE. But transactions have a deeper purpose: guaranteeing that a set of operations either all succeed as a block or never happened at all.
Think of a bank transfer. Two steps are required: debit account A by 30, then credit account B by 30. If the server crashes between the two, you have debited without crediting: 30 just vanished. That is exactly the kind of disaster a transaction prevents.
A transaction groups several instructions into an atomic block: either all of them succeed and become permanent at once (COMMIT), or one fails and everything is rolled back as if nothing happened (ROLLBACK). The database returns exactly to the state it was in before BEGIN.
Rollback: the safety net. If you spot a problem mid-way, ROLLBACK wipes the slate cleanly:
-- ROLLBACK demo: Alice's balance stays the same
CREATE TABLE comptes (id INTEGER, nom TEXT, solde INTEGER);
INSERT INTO comptes VALUES (1, 'Alice', 100);
INSERT INTO comptes VALUES (2, 'Bob', 50);
BEGIN;
UPDATE comptes SET solde = solde - 30 WHERE id = 1;
ROLLBACK;
SELECT nom, solde FROM comptes;
Alice stays at 100: the debit was fully rolled back.
Commit: validate a complete transfer. When both steps succeed, COMMIT makes them permanent together:
-- COMMIT demo: debit + credit validated as a block
CREATE TABLE comptes (id INTEGER, nom TEXT, solde INTEGER);
INSERT INTO comptes VALUES (1, 'Alice', 100);
INSERT INTO comptes VALUES (2, 'Bob', 50);
BEGIN;
UPDATE comptes SET solde = solde - 30 WHERE id = 1;
UPDATE comptes SET solde = solde + 30 WHERE id = 2;
COMMIT;
SELECT nom, solde FROM comptes;
Alice drops to 70, Bob rises to 80: the 30 transferred cleanly, no step left halfway.
Golden rule: any critical multi-step operation deserves a transaction. Wrap it with BEGIN at the start and COMMIT at the end. If a step fails or returns an unexpected result, issue a ROLLBACK: the database snaps back to its initial state, cleanly, with no half-modified data. This is the standard for transfers, orders, and linked updates across multiple tables.
À vous d'essayer, la base est déjà remplie. Avant de cliquer sur Exécuter, prédisez l'état final de la table : après l'INSERT de Léa (id 3), l'UPDATE de la ville de Marc (id 2) et le DELETE d'Alice (id 1) (combien de lignes restent, lesquelles, quelles valeurs) ? Lancez ensuite et comparez.
CREATE TABLE clients (id INTEGER, nom TEXT, email TEXT, ville TEXT);
INSERT INTO clients VALUES (1, 'Alice Durand', 'alice@exemple.fr', 'Dijon');
INSERT INTO clients VALUES (2, 'Marc Petit', 'marc@exemple.fr', 'Lyon');
INSERT INTO clients VALUES (3, 'Léa Martin', 'lea@exemple.fr', 'Dijon');
UPDATE clients SET ville = 'Besançon' WHERE id = 2;
DELETE FROM clients WHERE id = 1;
SELECT * FROM clients ORDER BY id;
🎯 Pratique
S'entraîner (clique pour ouvrir) :
✨ Prompt IA
Faites générer une requête de modification par l'IA et exigez un WHERE explicite + un SELECT de vérification avant exécution :
Table clients (id, nom, email, ville). Écris la requête UPDATE pour changer l'email du client dont l'id vaut 42 en 'nouveau@exemple.fr'. Règle obligatoire : la requête DOIT contenir un WHERE ciblant l'id, jamais un UPDATE global. Donne d'abord un SELECT de vérification montrant la ligne concernée, puis l'UPDATE. Explique le risque d'un UPDATE sans WHERE.
💬 Ré-explique sans regarder
Sans relire la réponse de l'IA : avec tes mots, pourquoi a-t-on exigé un WHERE ciblant l'id ET un SELECT de vérification avant l'UPDATE ?
WHERE, l'UPDATE réécrit l'email de TOUTES les lignes, c'est irréversible une fois validé. Le WHERE id = 42 limite l'action à la seule ligne voulue. Le SELECT portant le même WHERE sert de répétition : il montre EXACTEMENT les lignes qui seront touchées avant qu'on écrive quoi que ce soit. Bonus : enrober le tout dans BEGIN / COMMIT permet un ROLLBACK si le résultat surprend.Écrivez un UPDATE qui change la ville du client d'id 3 en 'Paris'. La requête DOIT contenir SET et un WHERE ciblant id = 3 (sinon elle modifierait toute la table).
⚖️ Juge le code de l'IA
Tu as demandé à l'IA de mettre la ville de Marc Petit (id 2) à jour en 'Lille'. Elle te répond ceci. Ton rôle de relecteur : l'accepter tel quel ou le rejeter, et dire pourquoi.
UPDATE clients
SET ville = 'Lille';
WHERE manque : cet UPDATE met TOUS les clients à Lille, pas seulement Marc Petit. C'est exactement la catastrophe du WHERE oublié, et une fois le COMMIT passé c'est irréversible. La requête correcte est UPDATE clients SET ville = 'Lille' WHERE id = 2;. Réflexe : avant de valider, lance SELECT * FROM clients WHERE id = 2; pour confirmer la cible.🧠 Rappel libre
Sans remonter dans la leçon : quelle commande ajoute une ligne, et que se passe-t-il si tu lances un UPDATE ou un DELETE sans WHERE ?
INSERT INTO ajoute une ligne (on nomme les colonnes, on donne les valeurs, sans fournir l'id auto-incrémenté). Un UPDATE ou un DELETE sans WHERE s'applique à TOUTE la table : il réécrit ou supprime chaque ligne, pas une seule. Réflexe : écrire le WHERE d'abord, le tester avec un SELECT, et travailler dans une transaction (BEGIN … COMMIT/ROLLBACK) pour pouvoir annuler.🔧 Débugue le code
Symptôme : ce script devait désactiver seulement Charlie (id 3), mais après exécution TOUS les clients ont actif = 0. Répare la requête, puis exécute.
CREATE TABLE clients (id INTEGER, nom TEXT, actif INTEGER);
INSERT INTO clients VALUES (1, 'Alice', 1), (2, 'Bob', 1), (3, 'Charlie', 1);
-- On veut désactiver UNIQUEMENT Charlie (id 3)
UPDATE clients SET actif = 0;
SELECT * FROM clients;
UPDATE clients SET actif = 0 n'a pas de clause WHERE, il s'applique donc à TOUTES les lignes. Alice et Bob sont désactivés au même titre que Charlie. La correction : ajouter WHERE id = 3 pour cibler uniquement Charlie : UPDATE clients SET actif = 0 WHERE id = 3;. Réflexe : sur un UPDATE ou un DELETE, écris toujours le WHERE en premier, et teste la condition avec un SELECT ... WHERE ... avant de modifier quoi que ce soit.Vous remplissez et videz des tables qui existent déjà. La dernière leçon remonte d'un cran : créer vos propres tables avec CREATE TABLE, types, clés et index, puis bloquer les injections SQL avec les requêtes préparées.
Leçon 7 : Concevoir et sécuriser →