2010-04-01 15 views
169

Ho una tabella e mi piacerebbe tirare una riga per id con valori di campo concatenati.Postgresql GROUP_CONCAT equivalente?

Nel mio tavolo, per esempio, ho questo:

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

E mi piacerebbe uscita:

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

In MySQL sono stato in grado di utilizzare la funzione di aggregazione GROUP_CONCAT, ma non sembra funzionare qui ... Esiste un equivalente per PostgreSQL o un altro modo per farlo?

+0

Non è una risposta, ma guarda che 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

possibile duplicato della funzione [Simulation group \ _concat MySQL in SQL Server?] (Http://stackoverflow.com/questions/451415/simulating-group-concat-mysql-function-in-sql-server) – ntalbs

risposta

155

Questo è probabilmente un buon punto di partenza (versione 8.4+ only):

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

array_agg restituisce un array, ma si può cast che per il testo e modificare, se necessario (vedi chiarimenti, di seguito).

Prima della versione 8.4, è necessario definire da soli prima dell'uso:

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

(parafrasato dalla documentazione PostgreSQL)

Chiarimenti:

  • Il risultato di gettare un array to text è che la stringa risultante inizia e termina con parentesi graffe. Queste parentesi devono essere rimosse con un metodo, se non sono desiderate.
  • Lanciare ANYARRAY a TEXT simula al meglio l'output CSV poiché gli elementi che contengono virgole incorporate sono doppiamente citati nell'output in stile CSV standard. Né array_to_string() o string_agg() (la funzione "group_concat" aggiunta in 9.1) cita le stringhe con le virgole incorporate, risultando in un numero errato di elementi nell'elenco risultante.
  • La nuova funzione 9.1 string_agg() NON esegue prima i risultati interni in TEXT. Quindi "string_agg (value_field)" genererebbe un errore se value_field è un intero. "string_agg (value_field :: text)" sarebbe richiesto. Il metodo array_agg() richiede solo un cast dopo l'aggregazione (piuttosto che un cast per valore).
+0

E in 9.0 listagg() –

+4

Per ottenere CSV la query dovrebbe essere: SELECT id_field, array_to_string (array_agg (value_field1), ','), array_to_string (array_agg (value_field2), ',') FROM data_table GROUP BY id_field – Nux

+2

Qui non è possibile utilizzare array_to_string in tutti i casi. Se valore_field contiene una virgola incorporata, il CSV risultante non è corretto. L'uso di array_agg() e il casting in TEXT cita correttamente le stringhe con le virgolette incorporate. L'unica avvertenza è che include anche le parentesi graffe iniziali e finali, da qui la mia affermazione "e la modifica secondo necessità". Modificherò per chiarire questo punto. –

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

farà come bene.

+4

Questo funziona anche prima di 9.0 - testato con 8.4. 5 – chrpes

+0

Eccellente !!! Per me va bene. Teste anche Postgres 8.3.6. Carri armati! – vandersondf

+0

È possibile fare qualcosa come in [questo commento] (http://stackoverflow.com/questions/2560946/postgresql-group-concat-equivalent#comment23843695_8803563), dove si aggrega in un certo ordine? Come gestireste il raggruppamento di una colonna e l'ordinamento di un altro (ad esempio, per concatenare le variabili all'interno di un insieme di dati longitudinale)? –

178

Since 9.0 questo è ancora più semplice:

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

Si noti che la sintassi consente anche di specificare l'ordine dei valori nella stringa (o matrice, utilizzando 'array_agg') ad es. 'string_agg (some_column, ',' ORDER BY some_column)' o anche 'string_agg (cognome || ',' || nomefile ';' ORDER BY cognome, nome)' – IMSoP

+0

@a_horse_with_no_name Vedo tanti dei tuoi fantastici messaggi su COSÌ, mentre sto lavorando su vari problemi di Postgres. Non vedo un modo per contattarti nel tuo profilo. Sei aperto a comunicare/lavorare su progetti al di fuori di SO? Mi scuso per il ping tramite commento se non. Se sei aperto a una possibile collaborazione/lavoro al di fuori di SO, puoi raggiungermi dal mio profilo, in tal caso: http://stackoverflow.com/users/2565593/steve-midgley - Stai facendo un lavoro straordinario qui - grazie ! (E agli editori mi sto affidando a meta commenti come questo per lasciare questo commento: http://meta.stackexchange.com/a/58715/278168) –

8

Prova in questo modo:

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