Dans cet article
- UNION combine les résultats de deux ou plusieurs requêtes SELECT en supprimant automatiquement les doublons
- UNION ALL est jusqu’à 30 % plus rapide que UNION car il ne trie pas les résultats pour dédoublonner
- Les requêtes combinées doivent avoir le même nombre de colonnes et des types de données compatibles
- UNION se distingue de JOIN : l’un empile des lignes verticalement, l’autre fusionne des colonnes horizontalement
- Les opérateurs ensemblistes INTERSECT et EXCEPT complètent UNION pour couvrir tous les cas de combinaison
- ORDER BY et GROUP BY s’appliquent après le UNION, sur le jeu de résultats final
Sommaire
- Comprendre SQL UNION et son fonctionnement
- Syntaxe de UNION et règles de compatibilité
- UNION vs UNION ALL : quand utiliser chacun
- Exemples concrets de SQL UNION étape par étape
- UNION vs JOIN vs INTERSECT vs EXCEPT
- Utiliser UNION avec GROUP BY et ORDER BY
- Erreurs fréquentes et bonnes pratiques
- Cas d’usage avancés en production
Quand j’enseigne le SQL à mes étudiants en BTS SIO, la question revient systématiquement : comment fusionner les résultats de plusieurs requêtes en une seule liste ? La réponse tient en un mot : UNION. Cet opérateur ensembliste est l’un des outils les plus puissants du langage SQL, et pourtant il reste souvent mal compris ou sous-exploité. Dans ce guide, je vous propose de maîtriser SQL UNION de A à Z, avec des exemples que vous pourrez reproduire immédiatement dans vos projets.
Comprendre SQL UNION et son fonctionnement
L’opérateur SQL UNION permet de combiner les résultats de deux ou plusieurs requêtes SELECT en un seul jeu de résultats. Concrètement, il empile les lignes retournées par chaque requête, comme si vous colliez deux tableaux l’un sous l’autre.
Prenons un exemple simple. Imaginons deux tables : clients_france et clients_belgique. Si je veux obtenir la liste complète de tous mes clients, j’écris :
SELECT nom, email FROM clients_france
UNION
SELECT nom, email FROM clients_belgique;
Le résultat contient toutes les lignes des deux tables, sans doublons. C’est le comportement par défaut de UNION : il effectue un tri implicite pour éliminer les lignes identiques. Ce mécanisme repose sur l’opération DISTINCT appliquée au résultat final.
Pour bien saisir la logique, pensez aux ensembles mathématiques. UNION réalise l’union ensembliste : A ∪ B contient tous les éléments de A et de B, chaque élément n’apparaissant qu’une fois. C’est exactement ce que fait SQL UNION avec vos lignes de données.
Si vous débutez en SQL et que vous souhaitez d’abord consolider vos bases sur les requêtes de sélection et de filtrage, je vous recommande de consulter mon guide d’exercices SQL avant de poursuivre.

Syntaxe de UNION et règles de compatibilité
La syntaxe de UNION est simple, mais elle impose des règles strictes que vous devez respecter sous peine d’erreur :
SELECT colonne1, colonne2, colonne3 FROM table_a
UNION
SELECT colonne1, colonne2, colonne3 FROM table_b;
Voici les trois règles fondamentales :
- Même nombre de colonnes : chaque SELECT doit retourner exactement le même nombre de colonnes. Si la première requête sélectionne trois colonnes, la seconde doit en sélectionner trois aussi.
- Types de données compatibles : les colonnes correspondantes (par position) doivent avoir des types compatibles. Un
VARCHARet unINTne peuvent pas être combinés directement. En revanche, unINTet unDECIMALfonctionnent car le SGBD effectue une conversion implicite. - Les noms de colonnes proviennent du premier SELECT : les alias et noms de colonnes du résultat final sont déterminés par la première requête. Si vous voulez des noms explicites, définissez vos alias dans le premier SELECT.
Un exemple avec alias :
SELECT nom AS nom_complet, 'France' AS pays FROM clients_france
UNION
SELECT nom, 'Belgique' FROM clients_belgique;
Le résultat affichera les colonnes nom_complet et pays, car ce sont les alias du premier SELECT. C’est une astuce que j’utilise fréquemment en cours pour identifier l’origine des données après un UNION.
Vous pouvez enchaîner autant de UNION que nécessaire :
SELECT nom, email FROM clients_france
UNION
SELECT nom, email FROM clients_belgique
UNION
SELECT nom, email FROM clients_suisse;
Cette requête combine les trois tables en un seul résultat, toujours sans doublons.
UNION vs UNION ALL : quand utiliser chacun
C’est la question que mes étudiants posent le plus souvent, et la réponse a un impact direct sur les performances de vos requêtes.
| Critère | UNION | UNION ALL |
|---|---|---|
| Doublons | Supprimés automatiquement | Conservés intégralement |
| Performance | Plus lent (tri + dédoublonnage) | Plus rapide (aucun tri) |
| Ordre des résultats | Non garanti (sauf ORDER BY explicite) | Non garanti (sauf ORDER BY explicite) |
| Cas d’usage typique | Listes uniques (emails, identifiants) | Agrégation de données, rapports, logs |
| Coût mémoire | Plus élevé (buffer de tri) | Minimal |
UNION ALL conserve toutes les lignes, y compris les doublons. Il n’effectue aucun tri ni aucune comparaison, ce qui le rend nettement plus performant. Sur des tables volumineuses, la différence peut atteindre 30 % de temps d’exécution en moins.
SELECT nom, email FROM clients_france
UNION ALL
SELECT nom, email FROM clients_belgique;
Ma règle en cours : utilisez UNION ALL par défaut et ne passez à UNION que si vous avez réellement besoin de supprimer les doublons. Trop de développeurs utilisent UNION systématiquement par habitude, ce qui pénalise les performances sans raison.
Un cas concret : si je combine les commandes du mois de janvier et du mois de février issues de tables partitionnées, il n’y aura jamais de doublons entre les deux mois. UNION ALL est alors le choix logique et performant.
Exemples concrets de SQL UNION étape par étape
Passons à la pratique avec des exemples que je donne régulièrement à mes étudiants. J’utilise ici une base de données fictive de gestion d’une école.
Exemple 1 : fusionner deux listes de contacts
Je veux obtenir la liste de toutes les personnes à contacter, qu’il s’agisse de professeurs ou de parents :
SELECT prenom, nom, email, 'Professeur' AS role
FROM professeurs
WHERE actif = 1
UNION
SELECT prenom, nom, email, 'Parent' AS role
FROM parents
WHERE email IS NOT NULL;
Chaque SELECT filtre ses propres données avec un WHERE avant que UNION ne combine les résultats. Les doublons sont supprimés : si un professeur est aussi parent avec le même email, il n’apparaîtra qu’une fois.
Exemple 2 : recherche multi-tables
Je veux rechercher le terme « Martin » dans plusieurs tables :
SELECT 'Etudiant' AS source, id, nom, prenom
FROM etudiants
WHERE nom LIKE '%Martin%'
UNION ALL
SELECT 'Professeur', id, nom, prenom
FROM professeurs
WHERE nom LIKE '%Martin%'
UNION ALL
SELECT 'Parent', id, nom, prenom
FROM parents
WHERE nom LIKE '%Martin%';
Ici, j’utilise UNION ALL car je veux voir toutes les occurrences, même si un Martin est à la fois parent et professeur. La colonne source me permet d’identifier l’origine de chaque résultat.

Exemple 3 : créer un rapport consolidé
Je veux un rapport des inscriptions par mois, en combinant les données de deux années :
SELECT MONTH(date_inscription) AS mois, COUNT(*) AS nb_inscrits, '2025' AS annee
FROM inscriptions_2025
GROUP BY MONTH(date_inscription)
UNION ALL
SELECT MONTH(date_inscription), COUNT(*), '2026'
FROM inscriptions_2026
GROUP BY MONTH(date_inscription)
ORDER BY annee, mois;
Notez que le ORDER BY final s’applique à l’ensemble du résultat combiné, pas à une seule des requêtes. C’est un point important que nous détaillons plus bas.
UNION vs JOIN vs INTERSECT vs EXCEPT
Cette section répond à une confusion très courante. Beaucoup de débutants mélangent UNION et JOIN, alors qu’ils répondent à des besoins complètement différents.
UNION vs JOIN : deux logiques opposées
UNION empile des lignes verticalement (plus de lignes, même nombre de colonnes). JOIN fusionne des colonnes horizontalement (même nombre de lignes, plus de colonnes). Voici un schéma mental :
- UNION : « Je veux les clients de France ET les clients de Belgique dans une seule liste. »
- JOIN : « Je veux les informations du client ET les détails de sa commande sur la même ligne. »
Utilisez UNION quand vos données ont la même structure mais proviennent de sources différentes. Utilisez JOIN quand vous devez croiser des informations complémentaires. Pour approfondir les jointures et notamment la combinaison WHERE + LEFT JOIN, consultez mon article dédié.
INTERSECT : l’intersection ensembliste
INTERSECT retourne uniquement les lignes communes aux deux requêtes :
SELECT email FROM clients_france
INTERSECT
SELECT email FROM clients_belgique;
Ce résultat affiche les emails présents dans les deux tables, soit les clients qui ont un compte en France et en Belgique. C’est l’équivalent de A ∩ B en théorie des ensembles.
EXCEPT (ou MINUS) : la différence ensembliste
EXCEPT retourne les lignes de la première requête qui n’existent pas dans la seconde :
SELECT email FROM clients_france
EXCEPT
SELECT email FROM clients_belgique;
Ce résultat affiche les clients exclusivement français. Attention, l’ordre des requêtes compte : EXCEPT n’est pas symétrique.
| Opérateur | Résultat | Doublons | Équivalent ensembliste |
|---|---|---|---|
| UNION | Toutes les lignes des deux requêtes | Supprimés | A ∪ B |
| UNION ALL | Toutes les lignes, doublons inclus | Conservés | – |
| INTERSECT | Lignes communes uniquement | Supprimés | A ∩ B |
| EXCEPT | Lignes de A absentes de B | Supprimés | A \ B |
| JOIN | Colonnes fusionnées horizontalement | Selon la condition | Produit cartésien filtré |
Utiliser UNION avec GROUP BY et ORDER BY
La combinaison de UNION avec les clauses d’agrégation et de tri est un sujet qui piège beaucoup de développeurs. Voici les règles à retenir.
ORDER BY avec UNION
Un seul ORDER BY est autorisé, et il doit se trouver à la fin de la dernière requête. Il s’applique à l’ensemble du résultat combiné :
SELECT nom, date_inscription FROM etudiants_2025
UNION ALL
SELECT nom, date_inscription FROM etudiants_2026
ORDER BY date_inscription DESC;
Si vous avez besoin de trier chaque sous-requête indépendamment avant le UNION, vous devez utiliser des sous-requêtes :
SELECT * FROM (
SELECT nom, date_inscription FROM etudiants_2025
ORDER BY date_inscription DESC
LIMIT 10
) AS top_2025
UNION ALL
SELECT * FROM (
SELECT nom, date_inscription FROM etudiants_2026
ORDER BY date_inscription DESC
LIMIT 10
) AS top_2026;
Cette technique est très utile pour récupérer les N premiers éléments de chaque source avant de les combiner.
GROUP BY avec UNION
Le GROUP BY s’applique à chaque SELECT individuellement, ou bien au résultat global via une sous-requête :
SELECT pays, SUM(montant) AS total
FROM (
SELECT pays, montant FROM ventes_en_ligne
UNION ALL
SELECT pays, montant FROM ventes_magasin
) AS toutes_ventes
GROUP BY pays
ORDER BY total DESC;
Cette approche est idéale quand vos données de ventes sont réparties dans plusieurs tables et que vous souhaitez un agrégat global. Pour vous entraîner sur ce type de requêtes complexes, explorez mes exercices SQL avancés.

Erreurs fréquentes et bonnes pratiques
Après plusieurs années à corriger les copies de mes étudiants, voici le top 5 des erreurs les plus courantes avec UNION :
Erreur 1 : nombre de colonnes différent
-- ERREUR : 3 colonnes vs 2 colonnes
SELECT nom, prenom, email FROM table_a
UNION
SELECT nom, prenom FROM table_b;
La solution : ajoutez une valeur NULL ou une constante pour compléter :
SELECT nom, prenom, email FROM table_a
UNION
SELECT nom, prenom, NULL AS email FROM table_b;
Erreur 2 : ORDER BY mal placé
-- ERREUR : ORDER BY dans le premier SELECT
SELECT nom FROM table_a ORDER BY nom
UNION
SELECT nom FROM table_b;
Le ORDER BY doit toujours être après le dernier SELECT de la chaîne UNION, ou dans une sous-requête encapsulée entre parenthèses.
Erreur 3 : utiliser UNION quand UNION ALL suffit
C’est l’erreur de performance la plus répandue. Chaque UNION déclenche un tri complet du jeu de résultats. Sur une table de plusieurs millions de lignes, cela peut transformer une requête de 200 ms en une requête de 3 secondes.
Erreur 4 : confondre UNION et JOIN
Comme je l’expliquais plus haut, UNION empile des lignes tandis que JOIN croise des colonnes. Si vous cherchez à enrichir vos données avec des informations d’une autre table, c’est un JOIN qu’il vous faut, pas un UNION.
Erreur 5 : oublier les alias dans le premier SELECT
Les noms de colonnes du résultat proviennent exclusivement du premier SELECT. Si vous oubliez d’y mettre des alias explicites, votre résultat aura des noms de colonnes peu lisibles.
Bonnes pratiques
- Préférez UNION ALL sauf besoin explicite de dédoublonnage
- Ajoutez une colonne source pour tracer l’origine des données
- Utilisez des alias explicites dans le premier SELECT
- Testez chaque SELECT individuellement avant de les combiner
- Vérifiez la compatibilité des types colonne par colonne
Cas d’usage avancés en production
Au-delà des exemples pédagogiques, UNION est un outil indispensable dans de nombreux scénarios de production.
Requêtes sur des tables partitionnées
Beaucoup d’architectures de bases de données partitionnent les données par période (mois, année) ou par région. UNION ALL permet de reconstituer une vue globale sans créer de vue matérialisée :
SELECT * FROM logs_2026_01
UNION ALL
SELECT * FROM logs_2026_02
UNION ALL
SELECT * FROM logs_2026_03;
Construire un menu déroulant dynamique
En développement web, on utilise souvent UNION pour créer des listes de sélection combinant des données de plusieurs sources :
SELECT 0 AS id, '-- Sélectionnez --' AS libelle, 0 AS ordre
UNION ALL
SELECT id, nom_categorie, 1 FROM categories
WHERE active = 1
ORDER BY ordre, libelle;
L’ajout d’une ligne fictive en tête de la liste avec UNION est une technique classique que j’enseigne en TP de développement web.
Migration et comparaison de données
Lors d’une migration de base de données, UNION combiné avec EXCEPT permet de comparer les données entre l’ancien et le nouveau système :
-- Lignes présentes dans l'ancien système mais absentes du nouveau
SELECT id, nom, email FROM ancien_systeme.clients
EXCEPT
SELECT id, nom, email FROM nouveau_systeme.clients;
Cette technique est précieuse pour valider l’intégrité d’une migration.
L’opérateur de concaténation || en SQL
Une question qui revient souvent concerne l’opérateur ||' '|| en SQL. Il ne s’agit pas d’un opérateur lié à UNION : c’est l’opérateur de concaténation de chaînes utilisé dans PostgreSQL, Oracle et SQLite. Il permet de combiner des valeurs textuelles :
-- PostgreSQL / Oracle / SQLite
SELECT prenom || ' ' || nom AS nom_complet FROM clients;
Sur SQL Server, on utilise plutôt la fonction CONCAT() ou l’opérateur +. Sur MySQL, CONCAT() est la méthode standard. Cet opérateur est documenté dans la documentation officielle PostgreSQL sur les fonctions de chaînes.
Compatibilité selon les SGBD
UNION et UNION ALL sont supportés par tous les SGBD relationnels majeurs : MySQL, PostgreSQL, SQL Server, Oracle, SQLite et MariaDB. En revanche, INTERSECT et EXCEPT ne sont pas disponibles partout. MySQL ne supporte INTERSECT et EXCEPT qu’à partir de la version 8.0.31. Avant cette version, il faut contourner avec des sous-requêtes et EXISTS. La documentation MySQL sur les opérations ensemblistes détaille les versions supportées.
Pour les étudiants qui travaillent avec SQL Server en environnement Microsoft, mon guide SQL Server 2022 couvre les spécificités de ce SGBD.
À retenir
- Utilisez UNION ALL par défaut et réservez UNION aux cas où le dédoublonnage est nécessaire
- Ajoutez toujours une colonne source (constante littérale) pour identifier l’origine des données combinées
- Placez le ORDER BY uniquement après le dernier SELECT de la chaîne UNION
- Vérifiez que chaque SELECT a le même nombre de colonnes avec des types compatibles
- Testez chaque requête SELECT individuellement avant de les assembler avec UNION
Questions fréquentes
Que fait l’opérateur UNION en SQL ?
UNION combine les résultats de deux ou plusieurs requêtes SELECT en un seul jeu de résultats. Il empile les lignes verticalement et supprime automatiquement les doublons. Les requêtes combinées doivent avoir le même nombre de colonnes avec des types de données compatibles. C’est l’équivalent de l’union ensembliste (A ∪ B) appliquée aux résultats de requêtes SQL.
Pourquoi utiliser UNION plutôt que JOIN ?
UNION et JOIN répondent à des besoins différents. UNION empile des lignes verticalement pour combiner des données de même structure provenant de sources différentes (par exemple, clients de France et clients de Belgique). JOIN fusionne des colonnes horizontalement pour croiser des informations complémentaires (par exemple, un client avec ses commandes). Utilisez UNION quand vos données ont la même structure ; utilisez JOIN quand vous devez enrichir une ligne avec des données d’une autre table.
Que signifie ||’ ‘|| en SQL ?
L’expression ||' '|| est l’opérateur de concaténation de chaînes utilisé dans PostgreSQL, Oracle et SQLite. Il permet d’assembler des valeurs textuelles avec un espace entre elles : prenom || ' ' || nom produit « Jean Dupont ». Ce n’est pas lié à UNION. Sur MySQL, on utilise CONCAT(prenom, ' ', nom) et sur SQL Server, prenom + ' ' + nom ou CONCAT().
Quelle est la différence entre UNION, INTERSECT et EXCEPT ?
Ces trois opérateurs sont des opérateurs ensemblistes. UNION retourne toutes les lignes des deux requêtes (A ∪ B). INTERSECT retourne uniquement les lignes communes aux deux requêtes (A ∩ B). EXCEPT retourne les lignes de la première requête absentes de la seconde (A \ B). Tous trois suppriment les doublons par défaut. Seul UNION dispose d’une variante ALL (UNION ALL) qui conserve les doublons.
UNION ALL est-il plus rapide que UNION ?
Oui, UNION ALL est significativement plus rapide que UNION. La raison est simple : UNION effectue un tri complet du résultat pour identifier et supprimer les doublons, ce qui consomme du temps CPU et de la mémoire. UNION ALL se contente d’empiler les résultats sans aucun traitement supplémentaire. Sur des volumes importants, la différence de performance peut atteindre 30 % ou plus. Utilisez UNION ALL par défaut et ne passez à UNION que si la suppression des doublons est réellement nécessaire.
Peut-on utiliser ORDER BY avec UNION ?
Oui, mais avec une contrainte : le ORDER BY doit être placé après le dernier SELECT de la chaîne UNION. Il s’applique alors à l’ensemble du résultat combiné. Il est interdit de placer un ORDER BY dans un SELECT intermédiaire, sauf si celui-ci est encapsulé dans une sous-requête entre parenthèses. Pour trier chaque partie indépendamment avant la combinaison, utilisez des sous-requêtes avec LIMIT.
Formatrice IT indépendante depuis 2016, ancienne étudiante BTS SIO SLAM. 6 ans d'expérience en entreprise.