SQL : INSERT, UPDATE, DELETE
Ajouter, modifier et supprimer des données — syntaxe, variantes, transactions et bonnes pratiques
🏠 Hub Programmation
🗄️ Cours SQL
🏗️ CREATE TABLE
📑 ORDER BY & LIMIT
DDL vs DML — deux familles de commandes
SQL est divisé en plusieurs sous-langages. Les deux principaux sont le DDL (Data Definition Language) et le DML (Data Manipulation Language). Le DDL concerne la structure de la base : créer, modifier ou supprimer des tables avec CREATE TABLE, ALTER TABLE et DROP TABLE. Le DML, lui, concerne les données à l’intérieur des tables. C’est le sujet de cette fiche.
| Catégorie | Commandes | Agit sur |
|---|---|---|
| DDL (structure) | CREATE, ALTER, DROP, TRUNCATE | Tables, colonnes, index |
| DML (données) | INSERT, UPDATE, DELETE, SELECT | Lignes dans les tables |
Les commandes DML sont réversibles avec un ROLLBACK (si tu es dans une transaction). Les commandes DDL sont généralement auto-committées — pas de retour en arrière possible. Cette distinction est essentielle quand tu travailles sur des données de production.
INSERT — insérer une ligne
La commande INSERT INTO ajoute une ou plusieurs nouvelles lignes dans une table. Tu spécifies les colonnes cibles puis les valeurs correspondantes. Les colonnes avec un DEFAULT ou AUTO_INCREMENT peuvent être omises — le SGBD les remplit automatiquement.
INSERT INTO clients (nom, email, ville)
VALUES (‘Alice’, ‘alice@email.com’, ‘Paris’);
— INSERT sans nommer les colonnes (déconseillé — fragile)
INSERT INTO clients
VALUES (NULL, ‘Bob’, ‘bob@email.com’, ‘Lyon’, NOW());
— ⚠️ Tu dois fournir une valeur pour CHAQUE colonne, dans le bon ordre
— Si l’ordre des colonnes change, la requête casse silencieusement
Bonne pratique : nomme toujours les colonnes dans ton INSERT. Le code est plus lisible, plus robuste, et il ne casse pas si quelqu’un ajoute une colonne à la table plus tard.
Au lieu de faire N requêtes INSERT séparées, tu peux insérer plusieurs lignes en une seule commande. C’est beaucoup plus performant car le SGBD n’exécute qu’un seul aller-retour réseau et un seul commit.
INSERT INTO clients (nom, email, ville) VALUES
(‘Alice’, ‘alice@email.com’, ‘Paris’),
(‘Bob’, ‘bob@email.com’, ‘Lyon’),
(‘Charlie’, ‘charlie@email.com’, ‘Marseille’);
— 3 lignes insérées en une seule requête
INSERT — variantes avancées
Cette variante est extrêmement utile pour dupliquer des données, archiver, ou remplir une table à partir d’une requête. Le SELECT remplace la clause VALUES — chaque ligne retournée par le SELECT est insérée dans la table cible.
INSERT INTO commandes_archive (id, client_id, montant, date)
SELECT id, client_id, montant, date
FROM commandes
WHERE date < ‘2025-01-01’;
— Copier des données entre tables
INSERT INTO newsletter_inscrits (email)
SELECT DISTINCT email FROM clients
WHERE opt_in = TRUE;
Un « upsert » est une opération qui insère une ligne si elle n’existe pas, et la met à jour si elle existe déjà (basé sur une contrainte UNIQUE ou PRIMARY KEY). C’est un pattern très courant pour les imports de données, les compteurs, et la synchronisation.
INSERT INTO compteurs (page_url, visites)
VALUES (‘/accueil’, 1)
ON DUPLICATE KEY UPDATE visites = visites + 1;
— PostgreSQL — ON CONFLICT
INSERT INTO compteurs (page_url, visites)
VALUES (‘/accueil’, 1)
ON CONFLICT (page_url) DO UPDATE SET
visites = compteurs.visites + 1;
— PostgreSQL — ignorer si doublon
INSERT INTO clients (email, nom)
VALUES (‘alice@email.com’, ‘Alice’)
ON CONFLICT (email) DO NOTHING;
L’upsert évite de faire un SELECT pour vérifier l’existence, puis un INSERT ou UPDATE séparé. C’est atomique (pas de race condition) et plus rapide. En MySQL, la contrainte peut être une PRIMARY KEY ou un index UNIQUE.
UPDATE — modifier des données
UPDATE modifie les valeurs de colonnes existantes. La clause WHERE détermine quelles lignes sont affectées. C’est la commande DML la plus dangereuse car un UPDATE sans WHERE modifie TOUTES les lignes de la table — une erreur très courante et souvent catastrophique en production.
UPDATE clients
SET ville = ‘Lyon’
WHERE id = 1;
— Modifier plusieurs colonnes en même temps
UPDATE clients
SET nom = ‘Alice Martin’,
email = ‘alice.martin@email.com’,
ville = ‘Bordeaux’
WHERE id = 1;
— Modifier plusieurs lignes avec une condition
UPDATE produits
SET prix = prix * 1.10 — augmentation de 10%
WHERE categorie = ‘Tech’;
— Utiliser des fonctions dans SET
UPDATE clients
SET email = LOWER(email),
updated_at = NOW()
WHERE email != LOWER(email); — seulement ceux qui ne sont pas déjà en minuscule
⚠️ TOUJOURS vérifier ton WHERE avant d’exécuter un UPDATE. Astuce : écris d’abord un SELECT avec le même WHERE pour voir quelles lignes seront affectées, puis remplace SELECT par UPDATE SET.
UPDATE avancé
Parfois tu as besoin de mettre à jour une table en fonction de données dans une autre table. L’UPDATE avec JOIN permet de croiser les tables directement dans la modification. La syntaxe varie selon le SGBD.
UPDATE commandes co
INNER JOIN clients c ON co.client_id = c.id
SET co.ville_client = c.ville
WHERE co.ville_client IS NULL;
— PostgreSQL — UPDATE … FROM
UPDATE commandes co
SET ville_client = c.ville
FROM clients c
WHERE co.client_id = c.id
AND co.ville_client IS NULL;
Quand tu ne peux pas utiliser un JOIN directement (ou pour une meilleure portabilité SQL standard), la sous-requête est une alternative universelle :
UPDATE clients
SET total_depense = (
SELECT COALESCE(SUM(montant), 0)
FROM commandes
WHERE commandes.client_id = clients.id
);
— Augmenter le prix des produits les plus vendus
UPDATE produits
SET prix = prix * 1.05
WHERE id IN (
SELECT produit_id FROM commandes
GROUP BY produit_id
HAVING COUNT(*) > 50
);
DELETE — supprimer des données
DELETE supprime des lignes d’une table. Comme UPDATE, la clause WHERE est cruciale — un DELETE sans WHERE supprime toutes les lignes de la table. La suppression est réversible si tu es dans une transaction (ROLLBACK), mais irréversible après un COMMIT.
DELETE FROM clients WHERE id = 42;
— Supprimer avec une condition
DELETE FROM sessions
WHERE derniere_activite < NOW() – INTERVAL 30 DAY;
— Supprimer les doublons (garder l’ID le plus petit)
DELETE c1 FROM clients c1
INNER JOIN clients c2
ON c1.email = c2.email
AND c1.id > c2.id; — MySQL
— Supprimer avec sous-requête
DELETE FROM commandes
WHERE client_id NOT IN (
SELECT id FROM clients
);
⚠️ Même réflexe qu’avec UPDATE : écris d’abord un SELECT avec le même WHERE pour vérifier les lignes qui seront supprimées. Puis remplace SELECT par DELETE.
En production, beaucoup d’applications ne suppriment jamais réellement les données. À la place, elles utilisent un « soft delete » : une colonne deleted_at qui contient la date de suppression. Les requêtes ajoutent un WHERE deleted_at IS NULL pour ignorer les lignes « supprimées ». Cela permet de récupérer des données accidentellement supprimées et de maintenir l’intégrité référentielle.
UPDATE clients
SET deleted_at = NOW()
WHERE id = 42;
— Lire seulement les clients « actifs »
SELECT * FROM clients WHERE deleted_at IS NULL;
— Restaurer un client supprimé
UPDATE clients SET deleted_at = NULL WHERE id = 42;
TRUNCATE vs DELETE
Les deux suppriment des données, mais de manière fondamentalement différente. DELETE supprime ligne par ligne, déclenche les triggers, respecte les FOREIGN KEY, et peut être annulé dans une transaction. TRUNCATE vide la table d’un coup en réinitialisant le stockage — c’est beaucoup plus rapide mais irréversible.
| Critère | DELETE FROM table | TRUNCATE TABLE table |
|---|---|---|
| Vitesse | ⚠️ Lent (ligne par ligne) | ✅ Très rapide (reset complet) |
| WHERE | ✅ Oui (suppression partielle) | ❌ Non (vide TOUTE la table) |
| ROLLBACK | ✅ Possible (dans une transaction) | ❌ Non (DDL, auto-commit) |
| Triggers | ✅ Déclenchés | ❌ Non déclenchés |
| AUTO_INCREMENT | Continue (ex : prochain id = 1001) | Reset à 1 |
| FOREIGN KEY | ✅ Vérifie les contraintes | ❌ Échoue si FK référencée |
| Type | DML (données) | DDL (structure) |
TRUNCATE TABLE logs;
— Supprimer toutes les lignes (lent, réversible)
DELETE FROM logs;
Transactions
Une transaction regroupe plusieurs opérations en un bloc atomique. Soit tout réussit (COMMIT), soit tout est annulé (ROLLBACK). C’est indispensable quand plusieurs modifications doivent rester cohérentes — par exemple, transférer de l’argent entre deux comptes. Si le débit réussit mais le crédit échoue, les deux doivent être annulés.
START TRANSACTION; — MySQL (BEGIN en PostgreSQL)
UPDATE comptes SET solde = solde – 100 WHERE id = 1; — débit
UPDATE comptes SET solde = solde + 100 WHERE id = 2; — crédit
— Si tout va bien :
COMMIT;
— Si erreur :
ROLLBACK; — annule les deux UPDATE
Bonne pratique en production : encadre toujours tes DELETE et UPDATE critiques dans une transaction. Si tu vois que le nombre de lignes affectées est anormal, ROLLBACK avant le COMMIT.
Erreurs fréquentes
| Erreur | Conséquence | Solution |
|---|---|---|
| UPDATE / DELETE sans WHERE | Modifie / supprime TOUTES les lignes | Toujours écrire le SELECT d’abord pour vérifier |
| INSERT sans nommer les colonnes | Casse si l’ordre des colonnes change | Toujours INSERT INTO table (col1, col2) |
| Violation de FOREIGN KEY | Erreur à l’INSERT ou DELETE | Vérifier les dépendances, utiliser ON DELETE CASCADE |
| Violation de UNIQUE | Erreur à l’INSERT | Utiliser ON CONFLICT / ON DUPLICATE KEY |
| Pas de transaction pour des opérations liées | Incohérence si crash au milieu | BEGIN / COMMIT / ROLLBACK |
| TRUNCATE sur une table avec FK | Erreur si d’autres tables référencent | Utiliser DELETE ou supprimer les FK d’abord |
Questions fréquentes
🏗️ CREATE TABLE
📑 ORDER BY & LIMIT
🔗 Jointures SQL
⚡ Les index SQL
🔍 Sous-requêtes
🗄️ Cours SQL complet
🏠 Hub Programmation
INSERT, UPDATE, DELETE en SQL — Manipuler les données
Référence : sql.sh INSERT INTO
