Skip to content

MERGE (UPSERT) – INSERT ou UPDATE (Standard SQL)

Bonne lecture et bon apprentissage !
Junior TSAFACK – 08/08/2026
⏱️ Temps de lecture estimé : 5 minutes


Dans le langage SQL, la commande MERGE permet d’insérer ou de mettre à jour des données dans une table. Cette commande permet d’éviter d’effectuer plusieurs requêtes pour savoir si une donnée est déjà dans la base de données et ainsi adapter l’utilisation d’une requête pour ajouter ou une autre pour modifier la donnée existante. Cette commande peut aussi s’appeler « upset » (contraction de UPDATE + INSERT).

Bon à savoir : Bien que l’instruction ait été ajoutée dans le standard SQL:2003, les différents SGBD n’utilisent pas toutes les mêmes méthodes pour effectuer un UPSERT.


La syntaxe standard pour effectuer un MERGE consiste à utiliser une requête SQL semblable à celle ci-dessous :

MERGE INTO table1
USING table_reference
ON (conditions)
WHEN MATCHED THEN
UPDATE SET table1.colonne1 = valeur1,
table1.colonne2 = valeur2
DELETE WHERE conditions2
WHEN NOT MATCHED THEN
INSERT (colonne1, colonne3)
VALUES (valeur1, valeur3);

Explications détaillées :

  • MERGE INTO permet de sélectionner la table à modifier.
  • USING et ON permettent de lister les données sources et la condition de correspondance.
  • WHEN MATCHED permet de définir la condition de mise à jour lorsque la condition est vérifiée.
  • WHEN NOT MATCHED permet de définir la condition d’insertion lorsque la condition n’est pas vérifiée.

Reprenons l’exemple du système de votes du chapitre précédent avec la table « vote » :

Table « vote » :

id produit_id vote_count vote_first_date vote_last_date
1 46 2 2012-04-25 17:45:24 2013-02-16 09:47:02
2 39 4 2012-04-28 16:54:44 2013-02-14 21:04:35
3 49 1 2012-04-25 19:11:09 2013-01-06 20:32:57

Avec MERGE, nous pouvons insérer un nouveau vote ou mettre à jour un vote existant en une seule requête :

MERGE INTO vote v
USING (SELECT 50 AS produit_id, 1 AS vote_count, SYSDATE AS vote_date FROM dual) src
ON (v.produit_id = src.produit_id)
WHEN MATCHED THEN
UPDATE SET v.vote_count = v.vote_count + src.vote_count,
v.vote_last_date = src.vote_date
WHEN NOT MATCHED THEN
INSERT (produit_id, vote_count, vote_first_date, vote_last_date)
VALUES (src.produit_id, src.vote_count, src.vote_date, src.vote_date);

Explication :

  1. USING définit une source de données temporaire contenant le produit_id, le nombre de votes et la date.
  2. ON spécifie la condition de correspondance : on cherche si le produit existe déjà dans la table vote.
  3. Si le produit existe (WHEN MATCHED), on met à jour le compteur et la date du dernier vote.
  4. Si le produit n’existe pas (WHEN NOT MATCHED), on insère une nouvelle ligne.

Les systèmes de gestion de bases de données peuvent implémenter cette fonctionnalité soit de façon standard, en utilisant une commande synonyme ou en utilisant une syntaxe non standard.

SGBD Support et syntaxe
SQL Server MERGE (syntaxe standard)
Oracle MERGE (syntaxe standard, avec FROM dual pour la source)
DB2 MERGE (syntaxe standard)
Teradata MERGE (syntaxe standard)
EXASOL MERGE (syntaxe standard)
PostgreSQL INSERT ... ON CONFLICT DO UPDATE (non standard)
MySQL INSERT ... ON DUPLICATE KEY UPDATE (non standard)
SQLite INSERT ... ON CONFLICT DO UPDATE (depuis 3.24.0)

INSERT INTO vote (produit_id, vote_count, vote_first_date, vote_last_date)
VALUES (50, 1, NOW(), NOW())
ON CONFLICT (produit_id)
DO UPDATE SET
vote_count = vote_count + 1,
vote_last_date = NOW();

SQL Server :

MERGE INTO vote AS v
USING (VALUES (50, 1, GETDATE())) AS src (produit_id, vote_count, vote_date)
ON v.produit_id = src.produit_id
WHEN MATCHED THEN
UPDATE SET v.vote_count = v.vote_count + src.vote_count,
v.vote_last_date = src.vote_date
WHEN NOT MATCHED THEN
INSERT (produit_id, vote_count, vote_first_date, vote_last_date)
VALUES (src.produit_id, src.vote_count, src.vote_date, src.vote_date);

Oracle :

MERGE INTO vote v
USING (SELECT 50 AS produit_id, 1 AS vote_count, SYSDATE AS vote_date FROM dual) src
ON (v.produit_id = src.produit_id)
WHEN MATCHED THEN
UPDATE SET v.vote_count = v.vote_count + src.vote_count,
v.vote_last_date = src.vote_date
WHEN NOT MATCHED THEN
INSERT (produit_id, vote_count, vote_first_date, vote_last_date)
VALUES (src.produit_id, src.vote_count, src.vote_date, src.vote_date);
INSERT INTO vote (produit_id, vote_count, vote_first_date, vote_last_date)
VALUES (50, 1, datetime('now'), datetime('now'))
ON CONFLICT (produit_id)
DO UPDATE SET
vote_count = vote_count + 1,
vote_last_date = datetime('now');

1. Mise à jour conditionnelle avec DELETE

Section titled “1. Mise à jour conditionnelle avec DELETE”

Il est possible de supprimer une ligne lors d’une correspondance si une condition supplémentaire est remplie :

MERGE INTO vote v
USING (SELECT 50 AS produit_id, 0 AS vote_count FROM dual) src
ON (v.produit_id = src.produit_id)
WHEN MATCHED THEN
UPDATE SET v.vote_count = v.vote_count + src.vote_count
DELETE WHERE v.vote_count <= 0;

La source peut être une table réelle, une vue ou une sous-requête complexe :

MERGE INTO produit p
USING (
SELECT c.produit_id, SUM(c.quantite) AS total_vendu
FROM commande c
GROUP BY c.produit_id
) src
ON (p.id = src.produit_id)
WHEN MATCHED THEN
UPDATE SET p.stock = p.stock - src.total_vendu;

Méthode Standard SQL Portabilité Performance
MERGE (standard) Oui Moyenne (selon SGBD) Bonne
INSERT ... ON DUPLICATE KEY UPDATE Non (MySQL) Faible Très bonne
INSERT ... ON CONFLICT DO UPDATE Non (PostgreSQL) Faible Très bonne
SELECT + INSERT/UPDATE (2 requêtes) Oui Excellente Mauvaise (2 appels)

  1. Utilisez la syntaxe la plus adaptée à votre SGBD : Si vous utilisez PostgreSQL, préférez ON CONFLICT. Si vous utilisez Oracle ou SQL Server, utilisez MERGE.

  2. Testez les performances : Sur de très grandes tables, le MERGE peut être plus lent qu’une approche en deux étapes (d’abord un UPDATE, puis un INSERT des lignes non modifiées). Testez selon votre contexte.

  3. Faites attention aux transactions : MERGE est une opération atomique, mais il est recommandé de l’utiliser dans une transaction pour garantir la cohérence.

  4. Évitez les conditions complexes dans ON : L’utilisation d’expressions complexes peut dégrader les performances. Préférez des conditions simples sur des colonnes indexées.

  5. Préférez une solution portable si votre application doit fonctionner sur plusieurs SGBD : dans ce cas, utilisez une approche avec SELECT puis INSERT/UPDATE gérée par le code applicatif.


Vous savez désormais comment effectuer un UPSERT avec MERGE. Mais que faire si vous souhaitez vider complètement une table tout en conservant sa structure, et ce de manière très rapide ?

👉 Chapitre 25 : TRUNCATE TABLE – Vider une table


Bonne continuation !
Junior TSAFACK – 08/08/2026