SQL Pratique
ARRAY_AGG et JSON en SQL : agréger vos données
7 min de lecture

ARRAY_AGG et JSON en SQL : agréger vos données

Découvrez ARRAY_AGG et les fonctions JSON SQL pour agréger des données complexes. Exemples concrets, pièges à éviter et cas d'usage en entretien.

Avatar de Thomas LeroyThomas Leroy

Agréger des lignes en tableau ou en objet JSON directement dans une requête SQL, c'est possible — et c'est ce que font ARRAY_AGG et les fonctions JSON natives de votre SGBD. Ces outils transforment des résultats multi-lignes en structures de données lisibles en une seule passe, sans post-traitement applicatif. En entretien data, maîtriser ces fonctions vous distingue immédiatement des candidats qui ne connaissent que GROUP BY et COUNT.

Cet article explore ARRAY_AGG, JSON_AGG, JSON_OBJECT_AGG et leurs équivalents dans les principaux SGBD (PostgreSQL, MySQL, SQLite, BigQuery). Vous trouverez des exemples concrets, un tableau comparatif entre bases de données, et les erreurs classiques à éviter.

📌 Ce qu'il faut retenir

  • ARRAY_AGG regroupe des valeurs d'une colonne en tableau, compatible PostgreSQL et BigQuery
  • JSON_AGG produit un tableau JSON à partir de lignes entières ou d'expressions
  • JSON_OBJECT_AGG construit un objet JSON avec des paires clé-valeur
  • Ces fonctions s'utilisent avec GROUP BY et acceptent ORDER BY en interne

Pourquoi agréger en tableau ou en JSON ?

Dans une base relationnelle classique, chaque relation est représentée par des lignes séparées. Pourtant, de nombreux cas métier nécessitent de consolider ces lignes en une seule cellule structurée : liste des commandes d'un client, tags associés à un article, historique d'actions d'un utilisateur.

Sans ARRAY_AGG ou JSON_AGG, vous êtes forcé de récupérer toutes les lignes côté application et de les regrouper manuellement. C'est coûteux en mémoire réseau et en logique de code. Avec ces fonctions, le SGBD fait le travail en une seule requête.

Ces cas d'usage apparaissent fréquemment dans les APIs REST, les exports de données et les pipelines ETL. Les connaître en entretien montre que vous pensez performance et maintenabilité.

ARRAY_AGG : regrouper des valeurs en tableau

Syntaxe de base

SELECT
  client_id,
  ARRAY_AGG(produit_nom) AS produits_achetes
FROM commandes
GROUP BY client_id;

Ce résultat retourne une ligne par client avec un tableau de tous les produits commandés. Sans ARRAY_AGG, il faudrait autant de lignes que de commandes par client.

Trier les éléments du tableau

ARRAY_AGG accepte un ORDER BY interne, ce qui est particulièrement utile pour les séquences chronologiques :

SELECT
  utilisateur_id,
  ARRAY_AGG(page_visitee ORDER BY visite_at ASC) AS parcours
FROM visites
GROUP BY utilisateur_id;

Cette requête reconstruit le parcours de navigation de chaque utilisateur dans l'ordre chronologique — un cas classique d'analyse de tunnel. Vous pouvez approfondir ce type d'analyse dans l'article sur l'analyse d'un tunnel de conversion e-commerce.

Éliminer les doublons avec DISTINCT

SELECT
  article_id,
  ARRAY_AGG(DISTINCT tag_nom) AS tags_uniques
FROM articles_tags
GROUP BY article_id;

DISTINCT à l'intérieur d'ARRAY_AGG filtre les valeurs dupliquées avant de construire le tableau. Notez que DISTINCT et ORDER BY ne sont pas combinables dans la même ARRAY_AGG sous PostgreSQL.

⚠️ Attention

Sous PostgreSQL, combiner DISTINCT et ORDER BY dans ARRAY_AGG génère une erreur. Si vous avez besoin des deux, utilisez une sous-requête intermédiaire pour dédoublonner avant d'agréger.

JSON_AGG : agréger des lignes en tableau JSON

Principe et cas d'usage

JSON_AGG (PostgreSQL, BigQuery) est similaire à ARRAY_AGG, mais produit un tableau JSON plutôt qu'un tableau natif. Elle est idéale pour construire des réponses API directement en base.

SELECT
  client_id,
  JSON_AGG(
    JSON_BUILD_OBJECT(
      'commande_id', commande_id,
      'montant', montant,
      'date', commande_date
    ) ORDER BY commande_date DESC
  ) AS commandes_json
FROM commandes
GROUP BY client_id;

Cette requête produit une colonne contenant un tableau JSON structuré par client — exactement le format attendu par la plupart des APIs REST modernes.

Filtrer avec FILTER

PostgreSQL permet d'ajouter un filtre conditionnel directement dans l'agrégation :

SELECT
  client_id,
  JSON_AGG(produit_nom) FILTER (WHERE statut = 'livre') AS produits_livres
FROM commandes
GROUP BY client_id;

Le mot-clé FILTER (WHERE ...) applique une condition avant l'agrégation. C'est plus propre et plus performant qu'un CASE WHEN imbriqué. Cette technique se rapproche des usages avancés décrits dans le guide CASE WHEN SQL avancé.

JSON_OBJECT_AGG : construire des objets clé-valeur

JSON_OBJECT_AGG(clé, valeur) construit un objet JSON unique à partir de paires de colonnes. Très utile pour pivoter des données dynamiquement.

SELECT
  produit_id,
  JSON_OBJECT_AGG(langue_code, traduction_texte) AS traductions
FROM traductions
GROUP BY produit_id;

Résultat pour un produit donné :

{"fr": "Chaise", "en": "Chair", "de": "Stuhl"}

C'est une alternative élégante au PIVOT statique quand les clés ne sont pas connues à l'avance.

💡 Bon à savoir

Sous MySQL 8+, utilisez JSON_ARRAYAGG et JSON_OBJECTAGG (sans underscore dans le nom) pour obtenir des comportements similaires à JSON_AGG et JSON_OBJECT_AGG de PostgreSQL.

Comparatif par SGBD

Fonction PostgreSQL MySQL 8+ BigQuery SQLite
Tableau natif ARRAY_AGG Non supporté ARRAY_AGG Non supporté
Tableau JSON JSON_AGG JSON_ARRAYAGG JSON_ARRAYAGG JSON_GROUP_ARRAY
Objet JSON JSON_OBJECT_AGG JSON_OBJECTAGG JSON_OBJECTAGG JSON_GROUP_OBJECT
ORDER BY interne ✅ Oui ✅ Oui ✅ Oui ❌ Non
FILTER clause ✅ Oui ❌ Non ❌ Non ❌ Non

Performances et pièges fréquents

Taille des tableaux générés

ARRAY_AGG et JSON_AGG chargent toutes les valeurs en mémoire avant de retourner le résultat. Sur des tables avec des millions de lignes et des groupes très larges, cela peut provoquer des dépassements mémoire ou des temps de réponse dégradés.

Il est conseillé de limiter la taille des tableaux avec un LIMIT dans une sous-requête ou de combiner avec une fenêtre temporelle (last 90 days par exemple).

NULL dans les agrégats

Par défaut, ARRAY_AGG inclut les valeurs NULL dans le tableau produit. Pour les exclure, utilisez un FILTER ou un WHERE préalable :

SELECT
  client_id,
  ARRAY_AGG(email) FILTER (WHERE email IS NOT NULL) AS emails_valides
FROM contacts
GROUP BY client_id;

Sans cette précaution, vous obtenez des tableaux comme ["alice@ex.com", null, "bob@ex.com"] qui nécessitent un nettoyage côté application.

Dépendance au SGBD

Ces fonctions ne sont pas standardisées dans le SQL ANSI. Si votre projet doit tourner sur plusieurs SGBD, encapsulez ces appels dans des vues ou des fonctions spécifiques à chaque moteur pour maintenir la portabilité.

Questions fréquentes

ARRAY_AGG et JSON_AGG : quelle différence concrète ?

ARRAY_AGG produit un tableau natif du SGBD (type array en PostgreSQL), utile pour des opérations SQL ultérieures comme UNNEST. JSON_AGG produit un tableau JSON (type json ou jsonb), idéal pour des échanges avec des APIs ou des exports. Choisissez ARRAY_AGG si vous restez dans SQL, JSON_AGG si vous exportez vers une application externe.

Peut-on utiliser ARRAY_AGG sans GROUP BY ?

Oui, sur l'ensemble de la table. SELECT ARRAY_AGG(nom) FROM clients; retourne un seul tableau avec tous les noms. C'est utile pour construire des listes de valeurs de référence dans une seule requête, par exemple pour alimenter un filtre dynamique.

Comment dédoublonner dans JSON_AGG ?

Contrairement à ARRAY_AGG, JSON_AGG ne supporte pas directement DISTINCT. La solution consiste à dédoublonner dans une sous-requête ou une CTE avant d'appliquer JSON_AGG. Consultez le guide sur les CTE SQL pour structurer ce type de requête proprement.

Ces fonctions sont-elles évaluées en entretien ?

Oui, de plus en plus. Les questions portent souvent sur la capacité à éviter des jointures multiples et des traitements applicatifs. Savoir construire un JSON directement en SQL est une compétence valorisée en data engineering et en backend.

Comment extraire des éléments d'un tableau ARRAY_AGG ensuite ?

Sous PostgreSQL, utilisez UNNEST(tableau) pour éclater un tableau en lignes, ou l'opérateur [n] pour accéder à l'élément à l'index n (base 1). Par exemple : (ARRAY_AGG(produit_nom ORDER BY date))[1] retourne le premier produit commandé par chaque client.

Conclusion

ARRAY_AGG, JSON_AGG et JSON_OBJECT_AGG sont des fonctions d'agrégation avancées qui permettent de produire des structures de données complexes directement dans SQL. Elles réduisent les aller-retours entre la base de données et l'application, simplifient les pipelines ETL et apparaissent régulièrement dans les tests techniques data.

La clé est de choisir la bonne fonction selon votre SGBD et votre cas d'usage : tableau natif pour rester dans SQL, JSON pour exporter. Entraînez-vous sur des jeux de données réels pour consolider ces réflexes avant un entretien.

👉 Mettez en pratique ces fonctions sur SQL Pratique avec notre environnement d'exécution en ligne et nos exercices corrigés.

Prêt à vous entraîner ?

50 exercices SQL interactifs avec éditeur en ligne, chronomètre et feedback IA.

Voir les exercices