PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Verbinden von Arrays innerhalb einer Group by-Klausel

UNION ALL

Sie könnten mit UNION ALL "gegenschwenken". zuerst:

SELECT name, array_agg(c) AS c_arr
FROM  (
   SELECT name, id, 1 AS rnk, col1 AS c FROM tbl
   UNION ALL
   SELECT name, id, 2, col2 FROM tbl
   ORDER  BY name, id, rnk
   ) sub
GROUP  BY 1;

Angepasst, um die Reihenfolge der Werte zu erzeugen, die Sie später angefordert haben. Das Handbuch:

Fettdruck von mir.

LATERAL Unterabfrage mit VALUES Ausdruck

LATERAL erfordert Postgres 9.3 oder später.

SELECT t.name, array_agg(c) AS c_arr
FROM  (SELECT * FROM tbl ORDER BY name, id) t
CROSS  JOIN LATERAL (VALUES (t.col1), (t.col2)) v(c)
GROUP  BY 1;

Gleiches Ergebnis. Benötigt nur einen einzigen Durchgang über den Tisch.

Benutzerdefinierte Aggregatfunktion

Oder Sie könnten eine benutzerdefinierte Aggregatfunktion erstellen, wie in diesen verwandten Antworten beschrieben:

CREATE AGGREGATE array_agg_mult (anyarray)  (
    SFUNC     = array_cat
  , STYPE     = anyarray
  , INITCOND  = '{}'
);

Dann können Sie:

SELECT name, array_agg_mult(ARRAY[col1, col2] ORDER BY id) AS c_arr
FROM   tbl
GROUP  BY 1
ORDER  BY 1;

Oder, normalerweise schneller, aber kein Standard-SQL:

SELECT name, array_agg_mult(ARRAY[col1, col2]) AS c_arr
FROM  (SELECT * FROM tbl ORDER BY name, id) t
GROUP  BY 1;

Die hinzugefügte ORDER BY id (die an solche Aggregatfunktionen angehängt werden können) garantiert Ihr gewünschtes Ergebnis:

a | {1,2,3,4}
b | {5,6,7,8}

Oder Sie könnten an dieser Alternative interessiert sein:

SELECT name, array_agg_mult(ARRAY[ARRAY[col1, col2]] ORDER BY id) AS c_arr
FROM   tbl
GROUP  BY 1
ORDER  BY 1;

Was zweidimensionale Arrays erzeugt:

a | {{1,2},{3,4}}
b | {{5,6},{7,8}}

Das letzte kann durch das eingebaute array_agg() ersetzt werden (und sollte es auch sein, da es schneller ist!). in Postgres 9.5 oder höher - mit der zusätzlichen Fähigkeit, Arrays zu aggregieren:

SELECT name, array_agg(ARRAY[col1, col2] ORDER BY id) AS c_arr
FROM   tbl
GROUP  BY 1
ORDER  BY 1;

Gleiches Ergebnis. Das Handbuch:

Also nicht genau dasselbe wie unsere benutzerdefinierte Aggregatfunktion array_agg_mult();