2010-04-01 13 views
169

J'ai une table et j'aimerais tirer une ligne par identifiant avec des valeurs de champs concaténées.Postgresql GROUP_CONCAT équivalent?

Dans ma table, par exemple, j'ai ceci:

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

Et je voudrais sortie:

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

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 une autre façon d'accomplir cela?

+0

Pas une réponse, mais Vérifions http://www.postgresonline.com/journal/index.php? /archives/14-CrossTab-Queries-in-PostgreSQL-using-tablefunc-contrib.html. – Kuberchaun

+1

http://stackoverflow.com/questions/1943433/postgresql-concat-ws-like-function –

+0

duplication possible de [Simuler le groupe \ _concat MySQL fonction dans SQL Server?] (Http://stackoverflow.com/questions/451415/simulant-groupe-concat-mysql-fonction-dans-sql-server) – ntalbs

Répondre

155

Ceci 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 

array_agg retourne un tableau, mais vous pouvez CAST que texte et modifier au besoin (voir précisions ci-dessous).

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

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

(paraphrase de la documentation PostgreSQL)

Clarifications:

  • Le résultat de la coulée d'un tableau en texte est que la chaîne résultante commence et se termine par des accolades. Ces accolades doivent être retirées par une méthode quelconque, si elles ne sont pas souhaitées.
  • La fonction ANYARRAY vers TEXT simule mieux la sortie CSV car les éléments contenant des virgules incorporées sont indiqués entre guillemets dans la sortie dans le style CSV standard. Ni array_to_string() ni string_agg() (la fonction "group_concat" ajouté en 9.1) ne propose des chaînes avec des virgules incorporé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 les résultats internes en TEXT en premier. Donc "string_agg (value_field)" générerait une erreur si value_field est un entier. "string_agg (value_field :: text)" serait requis. La méthode array_agg() nécessite seulement une conversion après l'agrégation (plutôt qu'une distribution par valeur).
+0

Et dans 9.0 vous aurez listagg() –

+4

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

+2

Vous ne pouvez pas utiliser array_to_string dans tous les cas ici. Si votre valeur_field contient une virgule incorporée, le CSV résultant est incorrect. L'utilisation de array_agg() et la conversion en TEXT citent correctement les chaînes avec des virgules incorporées. Le seul inconvénient est qu'il comprend également les accolades de début et de fin, d'où ma déclaration "et modifier au besoin". Je vais modifier pour clarifier ce point. –

30
SELECT array_to_string(array(SELECT a FROM b),', '); 

fera aussi bien.

+4

Celui-ci fonctionne également avant 9.0 - testé avec 8.4. 5 – chrpes

+0

Excellent! Travaille pour moi. Teste aussi Postgres 8.3.6. Réservoirs! – vandersondf

+0

Est-il possible de faire quelque chose comme dans [ce commentaire] (http://stackoverflow.com/questions/2560946/postgresql-group-concat-equivalent#comment23843695_8803563), où vous regroupez dans un certain ordre? Comment gérez-vous le regroupement d'une colonne et la commande par une autre (par exemple, concaténer des variables dans un ensemble de données longitudinales)? –

178

Since 9.0 cela est encore plus facile:

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

Notez que la syntaxe vous permet également de spécifier l'ordre des valeurs dans la chaîne (ou tableau, en utilisant 'array_agg'), par ex. 'string_agg (une_colonne, ',' ORDER BY une_colonne)' ou encore 'chaine_agg (nom de famille || ',' || prénom, ';' ORDER BY nom de famille, prénom)' – IMSoP

+0

@a_horse_with_no_name Je vois tant de vos meilleurs posts sur Alors que je travaille sur différents problèmes Postgres. Je ne vois pas comment vous contacter dans votre profil. Êtes-vous prêt à communiquer/travailler sur des projets en dehors de SO? Toutes mes excuses pour vous avoir envoyé un ping via un commentaire si ce n'est pas le cas. Si vous êtes ouvert à une éventuelle collaboration/travail en dehors de SO, vous pouvez me joindre à partir de mon profil si oui: http://stackoverflow.com/users/2565593/steve-midgley - Vous faites un travail incroyable ici - merci ! (Et pour les éditeurs, je compte sur des commentaires méta comme celui-ci pour laisser ce commentaire: http://meta.stackexchange.com/a/58715/278168) –

8

Essayez comme ceci:

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