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 |
⚠️ Attention
Sous MySQL, la longueur maximale de GROUP_CONCAT est limitée à 1024 caractères par défaut. Si vous concaténez de nombreuses valeurs longues, augmentez la limite avec SET SESSION group_concat_max_len = 100000; avant votre requête, sinon le résultat sera tronqué silencieusement.
Utiliser STRING_AGG comme fonction fenêtre
Une fonctionnalité moins connue : STRING_AGG peut s'utiliser comme fonction fenêtre SQL avec une clause OVER(). Cela permet de concaténer les valeurs d'une partition sans réduire le nombre de lignes du résultat.
SELECT
user_id,
role,
STRING_AGG(role, ', ') OVER (PARTITION BY user_id ORDER BY role) AS roles_cumules
FROM utilisateurs_roles;
Cette approche est particulièrement utile quand vous voulez conserver le détail ligne par ligne tout en affichant un récapitulatif agrégé en parallèle. C'est un cas régulièrement testé dans les entretiens techniques avancés.
Cas pratique : liste de produits par commande
Prenons un exemple e-commerce classique. La table lignes_commande contient commande_id, produit_nom et quantite. On veut un résumé par commande :
SELECT
commande_id,
STRING_AGG(
produit_nom || ' (x' || quantite::text || ')',
' | '
ORDER BY produit_nom
) AS detail_commande
FROM lignes_commande
GROUP BY commande_id;
Le résultat pourrait ressembler à : Clavier (x1) | Écran (x2) | Souris (x1). Ce format est directement exploitable dans un rapport ou une interface utilisateur sans traitement supplémentaire.
Pour aller plus loin sur les exercices pratiques de ce type, consultez notre article sur l'analyse d'un tunnel de conversion e-commerce en SQL.
Performances et bonnes pratiques
La concaténation de texte en SQL peut devenir coûteuse si le volume de données est important. Voici les points à surveiller :
- Limitez le nombre de lignes concaténées avec un filtre
WHEREou unLIMITdans une sous-requête - Évitez d'appliquer
STRING_AGGsur des colonnes non indexées sans filtre préalable - En MySQL, vérifiez toujours la valeur de
group_concat_max_lenen production - Préférez
STRING_AGGà la concaténation manuelle avec||dans une boucle côté applicatif
Pour les requêtes SQL récurrentes qui utilisent ces agrégations, pensez aussi aux vues SQL pour encapsuler la logique et faciliter la réutilisation.
Questions fréquentes
Quelle est la différence entre STRING_AGG et LISTAGG ?
LISTAGG est l'équivalent Oracle Database de STRING_AGG. Sa syntaxe est : LISTAGG(colonne, séparateur) WITHIN GROUP (ORDER BY colonne). Elle est standard SQL:2016 comme STRING_AGG, mais avec une syntaxe WITHIN GROUP propre à Oracle. Si vous travaillez sur Oracle, LISTAGG est la fonction à privilégier.
Les valeurs NULL sont-elles incluses dans la concaténation ?
Non. STRING_AGG et GROUP_CONCAT ignorent automatiquement les valeurs NULL lors de la concaténation, comme la plupart des fonctions d'agrégat SQL. Si vous voulez inclure une représentation des NULL, remplacez-les d'abord avec COALESCE(colonne, 'N/A') avant d'appliquer l'agrégation.
Peut-on utiliser STRING_AGG sans GROUP BY ?
Oui. Sans GROUP BY, STRING_AGG traite l'intégralité du résultat comme un seul groupe et retourne une seule ligne. C'est utile pour générer une liste globale depuis toute une table. En mode fenêtre avec OVER(), on peut aussi l'utiliser sans GROUP BY tout en conservant toutes les lignes.
Est-ce que STRING_AGG fonctionne dans BigQuery ?
Oui, BigQuery supporte STRING_AGG avec une syntaxe identique à PostgreSQL, y compris le ORDER BY interne et DISTINCT. C'est l'une des fonctions d'agrégation textuelle les plus utilisées dans les pipelines analytiques Google Cloud.
Comment gérer les doublons dans GROUP_CONCAT ?
Ajoutez le mot-clé DISTINCT juste après la parenthèse ouvrante : GROUP_CONCAT(DISTINCT colonne ORDER BY colonne SEPARATOR ', '). Cela élimine les valeurs identiques avant la concaténation. Attention : avec DISTINCT, l'ordre des valeurs dans le résultat peut parfois être imprévisible selon la version de MySQL.
Conclusion
STRING_AGG et GROUP_CONCAT sont des outils puissants pour transformer des données normalisées en résumés lisibles directement en SQL. Que vous travailliez sur PostgreSQL, MySQL, SQL Server ou BigQuery, ces fonctions vous permettent d'éviter des post-traitements applicatifs inutiles et de produire des rapports plus clairs.
Maîtriser leur syntaxe, leurs nuances de compatibilité et leurs bonnes pratiques vous donnera un avantage réel lors de vos entretiens techniques data. Entraînez-vous sur des cas concrets avec notre simulateur SQL en ligne pour consolider ces connaissances avant votre prochain test technique.
