Agréger des valeurs textuelles en une seule chaîne est une opération fréquente en analyse de données, et pourtant peu de candidats la maîtrisent en entretien. STRING_AGG (PostgreSQL, SQL Server, BigQuery) et GROUP_CONCAT (MySQL, SQLite) répondent exactement à ce besoin : transformer plusieurs lignes en une liste concaténée, directement dans votre requête SQL. Ce guide vous explique tout ce qu'il faut savoir pour les utiliser efficacement et les distinguer selon le SGBD.
📌 Ce qu'il faut retenir
STRING_AGGest la fonction standard dans PostgreSQL, SQL Server 2017+ et BigQueryGROUP_CONCATest l'équivalent MySQL/SQLite, avec une syntaxe légèrement différente- Les deux fonctions supportent un séparateur personnalisable et un tri interne via
ORDER BY - Ces fonctions s'utilisent avec ou sans
GROUP BY, y compris dans les fonctions fenêtre
Pourquoi concaténer des lignes en SQL ?
Imaginez une table commandes contenant plusieurs produits par commande. Sans agrégation textuelle, récupérer la liste des produits d'une commande impose plusieurs jointures ou un traitement côté applicatif. Avec STRING_AGG, une seule requête suffit.
Ce type d'opération apparaît régulièrement dans les tests techniques data analyst : rapports résumés, export de tags, affichage de catégories groupées ou encore génération de listes CSV dynamiques. Maîtriser ces fonctions vous fait gagner du temps et impressionne les recruteurs.
Les cas d'usage les plus courants sont :
- Regrouper les tags associés à un article ou un produit
- Lister les rôles d'un utilisateur dans une colonne unique
- Générer des rapports lisibles par des équipes non techniques
- Préparer des exports plats à partir de données normalisées
Syntaxe de STRING_AGG (PostgreSQL / SQL Server)
La syntaxe de STRING_AGG est simple et lisible. Elle prend 2 arguments obligatoires : la colonne à concaténer et le séparateur.
STRING_AGG(expression, séparateur)
Voici un exemple concret. On dispose d'une table utilisateurs_roles avec les colonnes user_id et role. On veut récupérer tous les rôles de chaque utilisateur en une seule ligne :
SELECT
user_id,
STRING_AGG(role, ', ') AS roles_liste
FROM utilisateurs_roles
GROUP BY user_id;
Le résultat affichera quelque chose comme admin, editor, viewer pour chaque utilisateur. Propre, lisible, efficace.
Trier les valeurs concaténées avec ORDER BY
STRING_AGG accepte une clause ORDER BY interne pour trier les valeurs avant de les concaténer. C'est un détail important pour produire des résultats déterministes, surtout en production.
SELECT
user_id,
STRING_AGG(role, ', ' ORDER BY role ASC) AS roles_liste
FROM utilisateurs_roles
GROUP BY user_id;
💡 Bon à savoir
Ajouter un ORDER BY interne à STRING_AGG est une bonne pratique en environnement de production. Sans tri, l'ordre des valeurs concaténées peut varier d'une exécution à l'autre selon le plan d'exécution du moteur SQL.
Syntaxe de GROUP_CONCAT (MySQL / SQLite)
Sous MySQL et SQLite, la fonction équivalente s'appelle GROUP_CONCAT. La logique est identique, mais la syntaxe diffère légèrement.
GROUP_CONCAT(expression ORDER BY expression ASC SEPARATOR ', ')
Même exemple avec MySQL :
SELECT
user_id,
GROUP_CONCAT(role ORDER BY role ASC SEPARATOR ', ') AS roles_liste
FROM utilisateurs_roles
GROUP BY user_id;
Attention : le mot-clé SEPARATOR remplace le second argument positionnel de STRING_AGG. Si vous omettez SEPARATOR, MySQL utilise une virgule par défaut (, sans espace), ce qui peut nuire à la lisibilité.
Éliminer les doublons avec DISTINCT
GROUP_CONCAT comme STRING_AGG supportent le mot-clé DISTINCT pour éviter les valeurs en double dans la concaténation :
-- MySQL
SELECT
user_id,
GROUP_CONCAT(DISTINCT role ORDER BY role ASC SEPARATOR ', ') AS roles_liste
FROM utilisateurs_roles
GROUP BY user_id;
-- PostgreSQL (via sous-requête ou DISTINCT dans l'agrégat)
SELECT
user_id,
STRING_AGG(DISTINCT role, ', ' ORDER BY role ASC) AS roles_liste
FROM utilisateurs_roles
GROUP BY user_id;
Tableau comparatif des deux fonctions
| Caractéristique | STRING_AGG (PostgreSQL / SQL Server) | GROUP_CONCAT (MySQL / SQLite) |
|---|---|---|
| Séparateur personnalisé | 2e argument positionnel | Mot-clé SEPARATOR |
| Tri interne | ORDER BY dans l'agrégat |
ORDER BY dans l'agrégat |
| DISTINCT supporté | Oui (PostgreSQL 16+, SQL Server limité) | Oui |
| Longueur max par défaut | Illimitée (selon mémoire) | 1024 caractères (paramètre group_concat_max_len) |
| Gestion des NULL | NULL ignorés automatiquement | NULL ignorés automatiquement |
| Compatibilité standard SQL | SQL:2016 (STRING_AGG) | Extension propriétaire MySQL |
