2010-04-01 7 views
169

Mam tabelę i chciałbym pobrać jeden wiersz na identyfikator z połączonymi wartościami pól.Postgresql GROUP_CONCAT odpowiednik?

W moim stole, na przykład, mam to:

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

I chciałbym wyjściowe:

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

W MySQL I był w stanie użyć funkcji zbiorczej GROUP_CONCAT, ale to chyba nie działa tutaj ... Czy istnieje odpowiednik PostgreSQL, lub inny sposób, aby to osiągnąć?

+0

nie odpowiedź, ale sprawdzić 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

możliwy duplikat funkcji [Simulating grupy \ _concat MySQL w SQL Server?] (Http://stackoverflow.com/questions/451415/simulating-group-concat-mysql-function-in-sql-server) – ntalbs

Odpowiedz

155

Prawdopodobnie jest to dobry punkt wyjścia (wersja 8.4+ tylko):

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

array_agg zwraca tablicę, ale można oddać, że do tekstu i edytować w zależności od potrzeb (patrz wyjaśnienia poniżej).

Przed wersją 8.4, trzeba je zdefiniować siebie przed użyciem:

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

(parafrazą z dokumentacji PostgreSQL)

Wyjaśnienie:

  • Wynikiem oddające array to text jest to, że wynikowy ciąg rozpoczyna się i kończy nawiasami klamrowymi. Te szelki muszą być usunięte za pomocą jakiejś metody, jeśli nie są pożądane.
  • Przesyłanie ANYARRAY do TEXT najlepiej symuluje wyjście CSV, ponieważ elementy zawierające osadzone przecinki są podwójnie cytowane w wynikach w standardowym stylu CSV. Ani array_to_string() ani string_agg() (funkcja "group_concat" dodana w 9.1) nie cytuje ciągów z osadzonymi przecinkami, co powoduje niepoprawną liczbę elementów na liście wynikowej.
  • Nowa funkcja 9.1 string_agg() NIE rzuca najpierw wewnętrznych wyników do TEXT. Tak więc "string_agg (value_field)" wygeneruje błąd, jeśli value_field jest liczbą całkowitą. "string_agg (value_field :: text)" byłby wymagany. Metoda array_agg() wymaga tylko jednego rzutowania po agregacji (zamiast rzutu na wartość).
+0

I w 9.0 trzeba będzie listagg() –

+4

Aby uzyskać CSV zapytanie powinno być: SELECT id_field, array_to_string (array_agg (value_field1), ' '), array_to_string (array_agg (value_field2),',') OD data_table GROUP BY id_field – Nux

+2

Nie można używać array_to_string we wszystkich przypadkach tutaj. Jeśli value_field zawiera zagnieżdżony przecinek, wynikowy plik CSV jest niepoprawny. Użycie array_agg() i rzutowanie do TEXT poprawnie cytuje ciągi z osadzonymi przecinkami. Jedynym zastrzeżeniem jest to, że zawiera ona również początkowe i końcowe nawiasy klamrowe, stąd moje zdanie "i edytuj je w razie potrzeby". Będę edytować, aby wyjaśnić ten punkt. –

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

Będzie również.

+4

Ten działa również przed 9.0 - testował go za pomocą 8.4. 5 – chrpes

+0

Doskonała !!! Pracuje dla mnie. Teste również Postgres 8.3.6. Czołgi! – vandersondf

+0

Czy można zrobić coś takiego w [this comment] (http://stackoverflow.com/questions/2560946/postgresql-group-concat-equivalent#comment23843695_8803563), gdzie zagregujesz w określonej kolejności? Jak obsługiwałbyś grupowanie według jednej kolumny i porządkowanie przez inną (na przykład, aby połączyć zmienne w podłużnym zbiorze danych)? –

178

Since 9.0 jest to jeszcze prostsze:

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

Należy zauważyć, że składnia pozwala również określić kolejność wartości w łańcuchu (lub tablicy, używając 'array_agg') np. 'string_agg (some_column, ',' ORDER BY some_column)' lub nawet 'string_agg (nazwisko || ',' || imię, ';' ORDER BY nazwisko, imię)' – IMSoP

+0

@a_horse_with_no_name Widzę tak wiele twoich wspaniałych postów na TAK, podczas gdy pracuję nad różnymi problemami PostgreSQL. Nie widzę sposobu, aby skontaktować się z Tobą w Twoim profilu. Czy jesteś otwarty na komunikację/pracę nad projektami poza SO? Przepraszam za wysłanie Ci polecenia za pomocą komentarza, jeśli nie. Jeśli jesteś otwarty na możliwą współpracę/pracę poza SO, możesz dotrzeć do mnie z mojego profilu, jeśli tak, to: http://stackoverflow.com/users/2565593/steve-midgley - Robisz niesamowitą pracę tutaj - dziękuję ! (I dla redaktorów polegam na komentarzach meta takich jak ten, aby zostawić ten komentarz: http://meta.stackexchange.com/a/58715/278168) –

8

Spróbuj tak:

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