298 votes

Équivalent de GROUP_CONCAT en Postgresql ?

J'ai un tableau et j'aimerais extraire une ligne par identifiant avec les valeurs des champs concaténées.

Dans mon tableau, par exemple, j'ai ceci :

TM67 | 4  | 32556
TM67 | 9  | 98200
TM67 | 72 | 22300
TM99 | 2  | 23009
TM99 | 3  | 11200

Et j'aimerais sortir :

TM67 | 4,9,72 | 32556,98200,22300
TM99 | 2,3    | 23009,11200

Dans MySQL, j'ai pu utiliser la fonction d'agrégation GROUP_CONCAT mais cela ne semble pas fonctionner ici... Existe-t-il un équivalent pour PostgreSQL, ou un autre moyen d'y parvenir ?

0 votes

Ce n'est pas une réponse, mais regardez postgresonline.com/journal/index.php?/archives/ .

1 votes

0 votes

311voto

a_horse_with_no_name Points 100769

Depuis la version 9.0 c'est encore plus facile :

SELECT id, 
       string_agg(some_column, ',')
FROM the_table
GROUP BY id

43 votes

Notez que la syntaxe vous permet également de spécifier l'ordre des valeurs dans la chaîne (ou le tableau, en utilisant la commande array_agg ) par exemple. string_agg(some_column, ',' ORDER BY some_column) ou même string_agg(surname || ', ' || forename, '; ' ORDER BY surname, forename)

11 votes

C'est génial que distinct fonctionne avec string_agg, donc on peut utiliser string_agg(distinct some_solumn, ',')

7 votes

Notez que vous pouvez avoir besoin de convertir la valeur de la colonne en TEXT s'il s'agit d'une valeur non-chiffrable (c'est-à-dire. uuid ). Cela ressemblerait à string_agg(some_column::text, ',')

286voto

Matthew Wood Points 4485

C'est probablement un bon point de départ (version 8.4+ uniquement) :

SELECT id_field, array_agg(value_field1), array_agg(value_field2)
FROM data_table
GROUP BY id_field

tableau_agg renvoie un tableau, mais vous pouvez le convertir en texte et l'éditer si nécessaire (voir les clarifications ci-dessous).

Avant la version 8.4, vous devez le définir vous-même avant de l'utiliser :

CREATE AGGREGATE array_agg (anyelement)
(
    sfunc = array_append,
    stype = anyarray,
    initcond = '{}'
);

(paraphrasé à partir de la documentation PostgreSQL)

Clarifications :

  • Le résultat de la conversion d'un tableau en texte est que la chaîne de caractères résultante commence et se termine par des accolades. Ces accolades doivent être supprimées par une méthode quelconque, si elles ne sont pas souhaitées.
  • La conversion de ANYARRAY en TEXTE permet de simuler au mieux la sortie d'un CSV, car les éléments qui contiennent des virgules intégrées sont cités deux fois dans la sortie, dans le style CSV standard. Ni array_to_string() ni string_agg() (la fonction "group_concat" ajoutée en 9.1) ne cite les chaînes avec des virgules intégrées, ce qui entraîne un nombre incorrect d'éléments dans la liste résultante.
  • La nouvelle fonction 9.1 string_agg() ne convertit PAS d'abord les résultats internes en TEXTE. Ainsi, "string_agg(champ_valeur)" génère une erreur si le champ_valeur est un entier. Il faudrait alors utiliser "string_agg(champ_valeur::texte)". La méthode array_agg() ne nécessite qu'un seul cast après l'agrégation (plutôt qu'un cast par valeur).

1 votes

Et en 9.0 vous aurez listagg()

7 votes

Pour obtenir le CSV, la requête doit être : SELECT id_field, array_to_string(array_agg(value_field1), ','), array_to_string(array_agg(value_field2),', ') FROM data_table GROUP BY id_field

2 votes

Vous ne pouvez pas utiliser array_to_string dans tous les cas ici. Si votre champ de valeur contient une virgule incorporée, le CSV résultant est incorrect. L'utilisation de array_agg() et la conversion en TEXTE permet de citer correctement les chaînes avec des virgules intégrées. Le seul problème est que cela inclut également les accolades de début et de fin, d'où ma déclaration "et modifiez si nécessaire". Je vais éditer pour clarifier ce point.

54voto

genobis Points 546
SELECT array_to_string(array(SELECT a FROM b),', ');

Je le ferai aussi.

0 votes

Est-il possible de faire quelque chose comme dans ce commentaire où l'on agrège dans un certain ordre ? Comment gérer le regroupement par une colonne et le classement par une autre (par exemple, pour concaténer des variables dans un ensemble de données longitudinales) ?

22voto

max_spy Points 1

Essayez comme ça :

select field1, array_to_string(array_agg(field2), ',')
from table1
group by field1;

2voto

ups Points 120

Et la version à travailler sur le type de tableau :

select
  array_to_string(
    array(select distinct unnest(zip_codes) from table),
    ', '
);

0 votes

Réponse en double, @max_spy a dit la même chose il y a cinq ans.

0 votes

@EmilVikström : vous avez le droit de vous tromper, mais lisez attentivement. Ce n'est pas seulement différent, mais j'ai donné un exemple, qui fonctionne avec le type de tableau - comme les codes postaux étant character varying(5)[] . Aussi, j'ai vérifié que pour mon but - unnest est nécessaire, sinon vous verrez ERROR: cannot accumulate arrays of different dimensionality .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X