UNION ALL
Du kan "motpivota" med UNION ALL
först:
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;
Anpassad för att producera den värdeordning du senare efterfrågade. Manualen:
Djärv betoning min.
LATERAL
underfråga
med VALUES
uttryck
LATERAL
kräver Postgres 9.3 eller senare.
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;
Samma resultat. Behöver bara en gång över bordet.
Anpassad aggregatfunktion
Eller du kan skapa en anpassad aggregatfunktion som diskuteras i dessa relaterade svar:
- Välja data till en Postgres array
- Finns det något liknande en zip()-funktion i PostgreSQL som kombinerar två arrayer?
CREATE AGGREGATE array_agg_mult (anyarray) (
SFUNC = array_cat
, STYPE = anyarray
, INITCOND = '{}'
);
Då kan du:
SELECT name, array_agg_mult(ARRAY[col1, col2] ORDER BY id) AS c_arr
FROM tbl
GROUP BY 1
ORDER BY 1;
Eller, vanligtvis snabbare, men inte 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;
Det tillagda ORDER BY id
(som kan läggas till sådana samlade funktioner) garanterar ditt önskade resultat:
a | {1,2,3,4}
b | {5,6,7,8}
Eller så kanske du är intresserad av detta alternativ:
SELECT name, array_agg_mult(ARRAY[ARRAY[col1, col2]] ORDER BY id) AS c_arr
FROM tbl
GROUP BY 1
ORDER BY 1;
Som producerar 2-dimensionella arrayer:
a | {{1,2},{3,4}}
b | {{5,6},{7,8}}
Den sista kan ersättas (och borde vara det, eftersom den är snabbare!) med den inbyggda array_agg()
i Postgres 9.5 eller senare - med dess extra förmåga att aggregera arrayer:
SELECT name, array_agg(ARRAY[col1, col2] ORDER BY id) AS c_arr
FROM tbl
GROUP BY 1
ORDER BY 1;
Samma resultat. Manualen:
Så inte exakt samma som vår anpassade aggregatfunktion array_agg_mult()
;