Postgresql GROUP_CONCAT-Äquivalent?

247

Ich habe eine Tabelle und möchte eine Zeile pro ID mit verketteten Feldwerten ziehen.

In meiner Tabelle habe ich zum Beispiel Folgendes:

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

Und ich möchte ausgeben:

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

In MySQL konnte ich die Aggregatfunktion verwenden GROUP_CONCAT, aber das scheint hier nicht zu funktionieren ... Gibt es ein Äquivalent für PostgreSQL oder eine andere Möglichkeit, dies zu erreichen?

TwixxyKit
quelle
1
Ich denke, die beste Antwort ist noch in einer anderen Frage: stackoverflow.com/a/47638417/243233
Jus12

Antworten:

237

Dies ist wahrscheinlich ein guter Ausgangspunkt (nur Version 8.4+):

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

array_agg gibt ein Array zurück, aber Sie können es in CAST umwandeln, um es nach Bedarf zu textieren und zu bearbeiten (siehe Erläuterungen unten).

Vor Version 8.4 müssen Sie diese vor der Verwendung selbst definieren:

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

(umschrieben aus der PostgreSQL-Dokumentation)

Erläuterungen:

  • Das Ergebnis des Umwandelns eines Arrays in Text ist, dass die resultierende Zeichenfolge mit geschweiften Klammern beginnt und endet. Diese Zahnspangen müssen auf irgendeine Weise entfernt werden, wenn sie nicht gewünscht werden.
  • Wenn Sie ANYARRAY in TEXT umwandeln, wird die CSV-Ausgabe am besten simuliert, da Elemente, die eingebettete Kommas enthalten, in der Ausgabe im Standard-CSV-Stil in doppelte Anführungszeichen gesetzt werden. Weder array_to_string () noch string_agg () (die in 9.1 hinzugefügte Funktion "group_concat") zitieren Zeichenfolgen mit eingebetteten Kommas, was zu einer falschen Anzahl von Elementen in der resultierenden Liste führt.
  • Die neue Funktion 9.1 string_agg () wandelt die inneren Ergebnisse NICHT zuerst in TEXT um. "String_agg (value_field)" würde also einen Fehler erzeugen, wenn value_field eine Ganzzahl ist. "string_agg (value_field :: text)" wäre erforderlich. Die array_agg () -Methode erfordert nur eine Umwandlung nach der Aggregation (anstelle einer Umwandlung pro Wert).
Matthew Wood
quelle
1
Und in 9.0 haben Sie listagg ()
Scott Bailey
6
Um CSV zu erhalten, sollte die Abfrage lauten: 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
Sie können hier nicht in allen Fällen array_to_string verwenden. Wenn Ihr value_field ein eingebettetes Komma enthält, ist die resultierende CSV falsch. Wenn Sie array_agg () verwenden und in TEXT umwandeln, werden Zeichenfolgen mit eingebetteten Kommas korrekt in Anführungszeichen gesetzt. Die einzige Einschränkung ist, dass es auch die beginnenden und endenden geschweiften Klammern enthält, daher meine Aussage "und nach Bedarf bearbeiten". Ich werde bearbeiten, um diesen Punkt zu verdeutlichen.
Matthew Wood
Zu Ihrer Information
Michael Rusch
255

Seit 9.0 ist das noch einfacher:

SELECT id, 
       string_agg(some_column, ',')
FROM the_table
GROUP BY id
ein Pferd ohne Name
quelle
32
Beachten Sie, dass Sie mit der Syntax auch die Reihenfolge der Werte in der Zeichenfolge (oder im Array array_agg) string_agg(some_column, ',' ORDER BY some_column)string_agg(surname || ', ' || forename, '; ' ORDER BY surname, forename)
festlegen können
8
Es ist großartig, dass es distinctmit string_agg funktioniert, also kann man es verwendenstring_agg(distinct some_solumn, ',')
arun
3
Beachten Sie, dass Sie den Spaltenwert möglicherweise TEXTumwandeln müssen , wenn es sich um einen nicht stringbaren Wert handelt (z. B. uuid). Dies würde aussehen wiestring_agg(some_column::text, ',')
Kendall
48
SELECT array_to_string(array(SELECT a FROM b),', ');

Wird auch tun.

Genobis
quelle
Ist es möglich, so etwas wie in diesem Kommentar zu tun, in dem Sie in einer bestimmten Reihenfolge aggregieren? Wie würden Sie mit der Gruppierung nach einer Spalte und der Reihenfolge nach einer anderen umgehen (z. B. um Variablen innerhalb eines Längsdatensatzes zu verketten)?
Michael A
15

Versuchen Sie es so:

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

und die Version, die für den Array-Typ verwendet werden soll :

select
  array_to_string(
    array(select distinct unnest(zip_codes) from table),
    ', '
);
Sławomir Lenart
quelle
Doppelte Antwort, @max_spy sagte das gleiche vor fünf Jahren
Emil Vikström
@ EmilVikström: Sie haben Recht, falsch zu liegen, aber lesen Sie sorgfältig. Es ist nicht nur anders, sondern ich habe ein Beispiel gegeben, das mit Array-Typ funktioniert - wie zip_codes character varying(5)[]. Außerdem habe ich überprüft, dass für meinen Zweck - unnest benötigt wird, sonst werden Sie sehen ERROR: cannot accumulate arrays of different dimensionality.
Sławomir Lenart
1

Mein Vorschlag in postgresql

SELECT cpf || ';' || nome || ';' || telefone  
FROM (
      SELECT cpf
            ,nome
            ,STRING_AGG(CONCAT_WS( ';' , DDD_1, TELEFONE_1),';') AS telefone 
      FROM (
            SELECT DISTINCT * 
            FROM temp_bd 
            ORDER BY cpf DESC ) AS y
      GROUP BY 1,2 ) AS x   
Lucas Cabral
quelle
1
Warum machst du ORDER BYin einer inneren Abfrage? Geht die Bestellung nicht trotzdem verloren?
Mypetlion
-1

Hoffe, dass die unten stehende Oracle-Abfrage funktioniert.

Select First_column,LISTAGG(second_column,',') 
    WITHIN GROUP (ORDER BY second_column) as Sec_column, 
    LISTAGG(third_column,',') 
    WITHIN GROUP (ORDER BY second_column) as thrd_column 
FROM tablename 
GROUP BY first_column
kiruba
quelle
Ich habe es auf rextester.com/l/postgresql_online_compiler getestet und es hat nicht funktioniert: 42883: Funktion listagg (Text, unbekannt, Text) existiert nicht
Manuel Romeiro
Oracle hat eine andere Syntax und Funktionen als Postgres.
Herman J. Radtke III