%% nav-debut : généré par gen_navigation.py, ne pas modifier à la main %%
> [!nav]
> ↩ [[Code et Développement/Développement d'Applications/SQL IV/SQL IV|Accueil · SQL IV]]
>
> | [[Code et Développement/Développement d'Applications/SQL IV/02_Garder les premières lignes - LIMIT\|← Garder les premières lignes : LIMIT]] | [[Code et Développement/Développement d'Applications/SQL IV/04_La jointure complète - FULL JOIN\|La jointure complète : FULL JOIN →]] |
> |:---|---:|
%% nav-fin %%
[[Code et Développement/Développement d'Applications/SQL IV/02_Garder les premières lignes - LIMIT|Garder les premières lignes - LIMIT]]
# Combiner deux résultats : `UNION`
## Introduction
Une jointure met deux tables **côte à côte** : elle ajoute des colonnes. Parfois, on a besoin de mettre deux résultats **l'un sous l'autre** : ajouter des lignes. C'est le rôle de `UNION`.
### Objectifs du chapitre
À la fin de ce chapitre, vous serez capable de :
- Mettre bout à bout les résultats de deux requêtes avec `UNION`.
- Choisir entre `UNION` et `UNION ALL`.
- Respecter les règles d'écriture d'une `UNION`.
---
## 1. Une nouvelle table : `Prospects`
En plus des tables *Clients* et *Commandes* (voir le chapitre [[Code et Développement/Développement d'Applications/SQL IV/01_Supprimer les doublons - DISTINCT|Supprimer les doublons : DISTINCT]]), l'entreprise garde une liste de **prospects** : des personnes intéressées qui ne sont pas encore clientes (ou qui ont été enregistrées deux fois par erreur).
**Table `Prospects`**
| id_prospect | nom_prospect | ville_prospect |
| ----------- | ------------ | -------------- |
| 1 | Lambert | Paris |
| 2 | Dupont | Lyon |
| 3 | Garnier | Nantes |
---
## 2. Jointure ou union ?
On nous demande : ***la liste de tous nos contacts, clients et prospects, (nom et ville) pour leur envoyer une invitation.***
Une jointure ne convient pas : nous ne voulons pas associer un client à un prospect, mais **réunir les deux listes en une seule**.
```mermaid
graph LR
A["Clients<br/>(5 lignes)"] --> U["UNION"]
B["Prospects<br/>(3 lignes)"] --> U
U --> R["Tous les contacts<br/>(les lignes des deux résultats, l'une sous l'autre)"]
```
| Je veux… | J'utilise… | Effet |
| --- | --- | --- |
| Associer des informations de deux tables (un client **et** ses commandes) | une jointure | ajoute des **colonnes** |
| Réunir deux listes semblables (les clients **puis** les prospects) | `UNION` | ajoute des **lignes** |
---
## 3. Syntaxe
```sql
SELECT champ1, champ2 FROM TableA
UNION
SELECT champ1, champ2 FROM TableB;
```
Chaque partie est une requête de sélection complète : elle peut avoir son propre `WHERE`, `GROUP BY`, `HAVING`.
---
## 4. Exemple
```sql
SELECT nom_client AS nom, ville_client AS ville
FROM Clients
UNION
SELECT nom_prospect, ville_prospect
FROM Prospects
ORDER BY nom;
```
### Étape 1 : chaque requête est exécutée
**Première requête** (Clients) :
| nom | ville |
| ------- | --------- |
| Martin | Paris |
| Dupont | Lyon |
| Bernard | Marseille |
| Petit | Lille |
| Robert | Bordeaux |
**Deuxième requête** (Prospects) :
| nom_prospect | ville_prospect |
| ------------ | -------------- |
| Lambert | Paris |
| Dupont | Lyon |
| Garnier | Nantes |
### Étape 2 : les résultats sont mis l'un sous l'autre
`UNION` place les lignes de la deuxième requête sous celles de la première, **puis supprime les lignes en double** (comme un `DISTINCT`). La ligne « Dupont, Lyon » existe dans les deux résultats : elle n'est gardée qu'une fois.
### Étape 3 : le `ORDER BY` trie le tout
| nom | ville |
| ------- | --------- |
| Bernard | Marseille |
| Dupont | Lyon |
| Garnier | Nantes |
| Lambert | Paris |
| Martin | Paris |
| Petit | Lille |
| Robert | Bordeaux |
Nous obtenons 7 contacts : 5 + 3 = 8 lignes, moins le doublon « Dupont, Lyon ».
---
## 5. `UNION` ou `UNION ALL` ?
| | `UNION` | `UNION ALL` |
| --- | --- | --- |
| Lignes en double | supprimées | gardées |
| Nombre de lignes dans notre exemple | 7 | 8 |
```sql
SELECT nom_client AS nom, ville_client AS ville
FROM Clients
UNION ALL
SELECT nom_prospect, ville_prospect
FROM Prospects
ORDER BY nom;
```
Avec `UNION ALL`, « Dupont, Lyon » apparaît deux fois.
> [!tip] Lequel choisir ?
> - On veut une **liste sans doublon** (envoyer une seule invitation par personne) → `UNION`.
> - On veut **toutes les lignes**, par exemple parce qu'on va les compter ou les additionner ensuite → `UNION ALL`. Supprimer des doublons fausserait le calcul.
> [!warning] Un doublon, c'est une ligne entière identique
> Comme pour `DISTINCT`, une ligne n'est supprimée que si **tous** ses champs sont identiques.
> Si on ajoute une colonne indiquant le type de contact, les deux « Dupont » ne sont plus identiques et restent tous les deux, même avec `UNION` :
>
> ```sql
> SELECT nom_client AS nom, ville_client AS ville, 'client' AS type_contact
> FROM Clients
> UNION
> SELECT nom_prospect, ville_prospect, 'prospect'
> FROM Prospects
> ORDER BY nom, type_contact;
> ```
>
> | nom | ville | type_contact |
> | ------- | --------- | ------------ |
> | Bernard | Marseille | client |
> | Dupont | Lyon | client |
> | Dupont | Lyon | prospect |
> | Garnier | Nantes | prospect |
> | Lambert | Paris | prospect |
> | Martin | Paris | client |
> | Petit | Lille | client |
> | Robert | Bordeaux | client |
>
> Ajouter une colonne qui indique d'où vient chaque ligne est souvent une bonne idée : on sait ensuite à quoi correspond chaque enregistrement.
---
## 6. Les règles à respecter
> [!important] Règles d'une `UNION`
> 1. **Même nombre de colonnes** dans chaque requête.
> 2. **Colonnes dans le même ordre** : la 1ʳᵉ colonne de la première requête est mise avec la 1ʳᵉ colonne de la deuxième, etc. Elles doivent contenir le même type d'information (on ne met pas des noms sous des dates).
> 3. **Les noms des colonnes sont ceux de la première requête.** C'est donc dans la première requête qu'on met les alias (`AS nom`, `AS ville`).
> 4. **Un seul `ORDER BY`, à la toute fin.** Il trie le résultat complet, et il utilise les noms de colonnes de la première requête.
> [!warning] Les colonnes sont associées par leur position, pas par leur nom
> ```sql
> SELECT nom_client, ville_client FROM Clients
> UNION
> SELECT ville_prospect, nom_prospect FROM Prospects;
> ```
> Cette requête fonctionne, mais le résultat est absurde : les villes des prospects se retrouvent dans la colonne des noms ! Le logiciel ne vérifie pas le sens des colonnes, c'est à vous de le faire.
---
## 7. Chaque partie peut avoir ses propres filtres
On nous demande : ***la liste des contacts parisiens, clients et prospects.***
```sql
SELECT nom_client AS nom FROM Clients WHERE ville_client = 'Paris'
UNION
SELECT nom_prospect FROM Prospects WHERE ville_prospect = 'Paris';
```
| nom |
| ------- |
| Martin |
| Lambert |
Chaque `WHERE` filtre **sa** requête, avant que les résultats soient réunis.
---
> [!important] Ce qu'il faut retenir
> - Jointure = côte à côte (ajoute des colonnes) ; `UNION` = l'un sous l'autre (ajoute des lignes).
> - `UNION` supprime les lignes en double, `UNION ALL` les garde.
> - Même nombre de colonnes, dans le même ordre ; noms de colonnes de la première requête ; un seul `ORDER BY` à la fin.
Prochaine étape, utiliser `UNION` pour garder **tous** les enregistrements de deux tables reliées :
[[Code et Développement/Développement d'Applications/SQL IV/04_La jointure complète - FULL JOIN|La jointure complète : FULL JOIN]]
%% nav-debut : généré par gen_navigation.py, ne pas modifier à la main %%
> [!nav]
> ↩ [[Code et Développement/Développement d'Applications/SQL IV/SQL IV|Accueil · SQL IV]]
>
> | [[Code et Développement/Développement d'Applications/SQL IV/02_Garder les premières lignes - LIMIT\|← Garder les premières lignes : LIMIT]] | [[Code et Développement/Développement d'Applications/SQL IV/04_La jointure complète - FULL JOIN\|La jointure complète : FULL JOIN →]] |
> |:---|---:|
%% nav-fin %%
---
🗓️ Historique
Dernière mise à jour : `30 octobre 2026`
Rédigé par : [[Vincent TELLIER]]