Question 1Dans INSERT INTO stock(sku, qty) VALUES ('A001', 15) ON CONFLICT(sku) DO UPDATE SET qty = qty + excluded.qty;, avec A001 déjà existant (qty 120), quel est le qty après l'UPSERT ?
UPSERT (ON CONFLICT) et applications du bulk INSERT
Utilise INSERT … ON CONFLICT(sku) DO UPDATE sur la table stock pour ajouter excluded.qty à l'A001 existant, insérer un A006 neuf, protéger les lignes existantes avec DO NOTHING, et faire un UPSERT en masse des 3 lignes de stock_in — en pratique.
Les données qu'on utilise — stock et stock_in
L'UPSERT (un mélange d'UPDATE et d'INSERT —
l'opération « mettre à jour si présent, insérer sinon » en une seule instruction) s'implémente via la syntaxe INSERT … ON CONFLICT(cle) DO UPDATE.
Si la ligne entre en collision avec une clé primaire ou une contrainte UNIQUE, la mise à jour s'exécute ; sinon, elle est insérée telle quelle.
ON CONFLICT DO UPDATE — mettre à jour si présent, insérer sinon
Écrire INSERT INTO table(...) VALUES (...) ON CONFLICT(col_cle) DO UPDATE SET col = ... signifie : si la ligne que tu tentes d'insérer entre en collision avec la clé déclarée dans ON CONFLICT (la clé primaire ou une colonne UNIQUE), la mise à jour DO UPDATE s'exécute ; sans collision, la ligne est simplement insérée.
À l'intérieur de DO UPDATE, un nom de table spécial excluded te permet de référencer « les valeurs de la ligne que tu tentais d'insérer ».
Écris qty = qty + excluded.qty et, en cas de collision, le qty existant est incrémenté du qty que tu tentais d'insérer.
Utilise qty = excluded.qty pour l'écrasement et qty = qty + excluded.qty pour l'accumulation, selon ton besoin.
-- Collision avec un sku existant → DO UPDATE ajoute au qty
INSERT INTO stock(sku, name, qty, price)
VALUES ('A001', 'Pen', 5, 80)
ON CONFLICT(sku) DO UPDATE SET qty = qty + excluded.qty;
-- Nouveau sku → pas de collision, simple insertion
INSERT INTO stock(sku, name, qty, price)
VALUES ('A006', 'Marker', 3, 120)
ON CONFLICT(sku) DO UPDATE SET qty = qty + excluded.qty;
SELECT sku, name, qty FROM stock WHERE sku IN ('A001', 'A006');
DO NOTHING — ne rien faire en cas de collision
Quand tu ne veux ni mettre à jour ni insérer — c'est-à-dire « ignorer silencieusement en cas de collision » — utilise ON CONFLICT(cle) DO NOTHING.
Sans collision la ligne est insérée ; en cas de collision la ligne est ignorée sans erreur.
Dans l'exemple ci-dessous, tenter d'insérer l'A002 existant avec DO NOTHING entre en collision et est ignoré, tandis que le nouvel A007 est inséré.
-- Ignorer en cas de collision (DO NOTHING)
INSERT INTO stock(sku, name, qty, price)
VALUES ('A002', 'Note', 999, 999)
ON CONFLICT(sku) DO NOTHING;
-- A002 garde ses valeurs initiales (qty 60 / price 250)
SELECT sku, name, qty, price FROM stock WHERE sku = 'A002';
UPSERT multi-lignes — combiner un INSERT en masse avec ON CONFLICT
Quand tu attaches ON CONFLICT à un INSERT multi-lignes — VALUES (...),(...),(...) séparés par des virgules — chaque ligne « met à jour en cas de collision, insère sinon » de façon indépendante.
Tu peux répercuter les données d'arrivage en une instruction, remplaçant une boucle procédurale qui branche entre UPDATE et INSERT par ligne par un seul SQL.
Même dans un UPSERT multi-lignes, excluded désigne toujours « la valeur que tu tentais d'insérer pour cette ligne », donc écrire qty = qty + excluded.qty applique « ajout pour les lignes existantes, insertion telle quelle pour les nouvelles » ligne par ligne.
L'exercice final de cet article est un UPSERT en masse des 3 lignes de stock_in (A001 / A004 / A006).
-- UPSERT multi-lignes : les lignes existantes accumulent qty et rafraîchissent price ; les nouvelles sont insérées
INSERT INTO stock(sku, name, qty, price)
VALUES
('A002', 'Note', 10, 260),
('A005', 'Glue', 20, 190),
('A007', 'Ruler', 15, 90)
ON CONFLICT(sku) DO UPDATE
SET qty = qty + excluded.qty,
price = excluded.price;
SELECT sku, name, qty, price FROM stock ORDER BY sku;
Vérification des connaissances
Répondez à chaque question une par une.
Question 2À quoi excluded réfère-t-il à l'intérieur du DO UPDATE d'un UPSERT ?
Question 3Quelle syntaxe utilises-tu pour ne jamais modifier les données existantes et ignorer silencieusement les collisions sans erreur ?