UNION et allons apprendre à l’utiliser pour combiner les résultats de deux déclarations SELECT ou pour simuler le comportement d’un FULL OUTER JOIN.
Conditions d’utilisation de l’opérateur SQL UNION
Nous allons utiliser l’opérateur SQL UNION pour combiner les résultats de deux déclarations SELECT.
Afin que cet opérateur fonctionne correctement et que les résultats puissent bien être combinés, il va falloir respecter les règles suivantes :
- Chacun des
SELECTdans unUNIONdoit posséder le même nombre de colonnes ; - Les colonnes doivent posséder le même type de données une à une dans chaque
SELECT(la première colonne du premierSELECTdoit posséder des données de même type que la première colonne du deuxièmeSELECTet etc.).
Notez bien que les colonnes sélectionnées peuvent avoir un nom différent entre les différents SELECT du moment que le type de données est le même. En cas de nom différent, et si nous voulons harmoniser les noms, nous pouvons tout à fait utiliser un alias.
Par défaut, l’opérateur SQL UNION ne va pas sélectionner les doublons dans les valeurs (les valeurs qui sont trouvées plusieurs fois n’apparaitront qu’une seule fois).
Nous allons par exemple pouvoir sélectionner la liste des noms et prénoms dans nos tables « users » et « employes » créées précédemment :
<!DOCTYPE html>
<html>
<head>
<title>Cours PHP / MySQL</title>
<meta charset='utf-8'>
</head>
<body>
<h1>Bases de données MySQL</h1>
<?php
$servname = "localhost"; $dbname = "cours"; $user = "root"; $pass = "root";
try{
$dbco = new PDO("mysql:host=$servname;dbname=$dbname", $user, $pass);
$dbco->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
/*L'opérateur SQL UNION*/
$sth = $dbco->prepare("
SELECT nom, prenom FROM employes
UNION
SELECT nom, prenom FROM users
");
$sth-> execute();
$resultat = $sth->fetchAll(PDO::FETCH_ASSOC);
echo '<pre>';
print_r($resultat);
echo '</pre>';
}
catch(PDOException $e){
echo "Erreur : " . $e->getMessage();
}
?>
</body>
</html>

Comme vous pouvez le voir, les valeurs dupliquées n’apparaissent qu’une fois. Notez bien qu’ici on sélectionne les noms et prénom dans chaque table qui vont représenter une entité et c’est bien sur cette entité nom + prénom que va être évaluée la duplication.
C’est pour cela qu’on a deux fois le prénom « Pierre » qui s’affiche, tout simplement car nos « Pierre » n’ont pas le même nom.
Si nous n’avions sélectionnés que les prénoms, le prénom « Pierre » ne se serait affiché qu’une fois :
<!DOCTYPE html>
<html>
<head>
<title>Cours PHP / MySQL</title>
<meta charset='utf-8'>
</head>
<body>
<h1>Bases de données MySQL</h1>
<?php
$servname = "localhost"; $dbname = "cours"; $user = "root"; $pass = "root";
try{
$dbco = new PDO("mysql:host=$servname;dbname=$dbname", $user, $pass);
$dbco->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
/*L'opérateur SQL UNION*/
$sth = $dbco->prepare("
SELECT prenom FROM employes
UNION
SELECT prenom FROM users
");
$sth-> execute();
$resultat = $sth->fetchAll(PDO::FETCH_ASSOC);
echo '<pre>';
print_r($resultat);
echo '</pre>';
}
catch(PDOException $e){
echo "Erreur : " . $e->getMessage();
}
?>
</body>
</html>

Si vous souhaitez obtenir toutes les valeurs (incluant les valeurs en double et etc.) alors il faudra utiliser UNION ALL.
<!DOCTYPE html>
<html>
<head>
<title>Cours PHP / MySQL</title>
<meta charset='utf-8'>
</head>
<body>
<h1>Bases de données MySQL</h1>
<?php
$servname = "localhost"; $dbname = "cours"; $user = "root"; $pass = "root";
try{
$dbco = new PDO("mysql:host=$servname;dbname=$dbname", $user, $pass);
$dbco->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
/*UNION ALL*/
$sth = $dbco->prepare("
SELECT prenom, nom FROM employes
UNION ALL
SELECT prenom, nom FROM users
");
$sth-> execute();
$resultat = $sth->fetchAll(PDO::FETCH_ASSOC);
echo '<pre>';
print_r($resultat);
echo '</pre>';
}
catch(PDOException $e){
echo "Erreur : " . $e->getMessage();
}
?>
</body>
</html>

Utiliser l’opérateur UNION pour simuler un FULL OUTER JOIN en MySQL
Rappel : un FULL OUTER JOIN est un type de jointures externes qui va récupérer toutes les données pour les colonnes sélectionnées de chacune des deux tables.
Le mot clef FULL OUTER JOIN n’est pas supporté en tant que tel par MySQL. Nous allons cependant pouvoir simuler un FULL OUTER JOIN en utilisant un LEFT JOIN et un RIGHT JOIN avec une clause WHERE pour ne pas avoir les données présentes dans les deux tables en double dans notre résultat final et en combinant les résultats obtenus avec un UNION.
Pour rappel, un LEFT JOIN va nous permettre de récupérer toutes les données de notre table de gauche ainsi que les données de la table de droite qui satisfont à la condition dans la jointure.
Un RIGHT JOIN va lui nous permettre de récupérer toutes les données de notre table de droite ainsi que les données de la table de gauche qui satisfont à la condition dans la jointure.
Ainsi, en s’arrêtant là, nous allons avoir les données de la table de droite qui satisfont à la condition de notre LEFT JOIN et les données de la table de gauche qui satisfont à la condition de notre RIGHT JOIN en double (puisque notre RIGHT JOIN récupère déjà toutes les données de la table de droite et notre LEFT JOIN récupère déjà toutes les données de la table de gauche).
Ainsi, nous allons utiliser une clause WHERE soit dans notre LEFT JOIN soit dans notre RIGHT JOIN pour ne pas sélectionner plus de données que ce qu’on doit.
Attention, on ne parle pas ici de supprimer les résultats dupliqués, on veut seulement tenter de simuler le résultat d’un FULL OUTER JOIN et pour cela il ne faut pas aller sélectionner deux fois les mêmes résultats. Il est possible que l’on ait des valeurs dupliquées au final s’il y en a dans nos colonnes à la base.
Essayons de simuler le comportement d’un FULL OUTER JOIN qui sélectionnerait tous les prénoms et noms de notre table « users » et tous les contenus et les dates des commentaires de notre tables « comments » :
<!DOCTYPE html>
<html>
<head>
<title>Cours PHP / MySQL</title>
<meta charset='utf-8'>
</head>
<body>
<h1>Bases de données MySQL</h1>
<?php
$servname = "localhost"; $dbname = "cours"; $user = "root"; $pass = "root";
try{
$dbco = new PDO("mysql:host=$servname;dbname=$dbname", $user, $pass);
$dbco->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//Simulation d'un FULL OUTER JOIN
$sth = $dbco->prepare("
SELECT u.prenom, u.nom, c.contenu, c.dateComment FROM users AS u
LEFT JOIN comments AS c ON u.id = c.userId
UNION ALL
SELECT u.prenom, u.nom, c.contenu, c.dateComment FROM users AS u
RIGHT JOIN comments AS c ON u.id = c.userId
WHERE u.id IS NULL
");
$sth-> execute();
$resultat = $sth->fetchAll(PDO::FETCH_ASSOC);
echo '<pre>';
print_r($resultat);
echo '</pre>';
}
catch(PDOException $e){
echo "Erreur : " . $e->getMessage();
}
?>
</body>
</html>

Ici, le premier SELECT sélectionne tous les prénoms et noms de notre table « users » ainsi que les contenus et dates de nos commentaires liés à un id utilisateur.
Le deuxième SELECT sélectionne lui uniquement les contenus et dates des commentaires qui n’ont pas d’utilisateur associé (WHERE u.id IS NULL).
En unissant ces deux SELECT avec un UNION ALL, cela nous permet donc d’obtenir tous les noms et prénoms de nos utilisateurs et tous les contenus et dates des commentaires.






