UNION ALL
Możesz „przeciwstawić się” za pomocą UNION ALL
po pierwsze:
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;
Przystosowany do tworzenia kolejności wartości, o które prosiłeś później. Podręcznik:
Pogrubiony nacisk na moje.
LATERAL
podzapytanie
z VALUES
wyrażenie
LATERAL
wymaga Postgresa 9.3 lub później.
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;
Ten sam wynik. Wystarczy jedno przejście nad stołem.
Niestandardowa funkcja agregująca
Lub możesz utworzyć niestandardową funkcję agregującą, jak omówiono w tych powiązanych odpowiedziach:
- Wybieranie danych do Tablica Postgresa
- Czy jest coś takiego jak funkcja zip() w PostgreSQL, która łączy dwie tablice?
CREATE AGGREGATE array_agg_mult (anyarray) (
SFUNC = array_cat
, STYPE = anyarray
, INITCOND = '{}'
);
Następnie możesz:
SELECT name, array_agg_mult(ARRAY[col1, col2] ORDER BY id) AS c_arr
FROM tbl
GROUP BY 1
ORDER BY 1;
Lub, zazwyczaj szybciej, ale nie w standardowym SQL:
SELECT name, array_agg_mult(ARRAY[col1, col2]) AS c_arr
FROM (SELECT * FROM tbl ORDER BY name, id) t
GROUP BY 1;
Dodany ORDER BY id
(które można dołączyć do takich funkcji agregujących) gwarantuje pożądany wynik:
a | {1,2,3,4}
b | {5,6,7,8}
A może zainteresuje Cię ta alternatywa:
SELECT name, array_agg_mult(ARRAY[ARRAY[col1, col2]] ORDER BY id) AS c_arr
FROM tbl
GROUP BY 1
ORDER BY 1;
Który tworzy tablice dwuwymiarowe:
a | {{1,2},{3,4}}
b | {{5,6},{7,8}}
Ten ostatni może zostać zastąpiony (i powinien być, ponieważ jest szybszy!) za pomocą wbudowanego array_agg()
w Postgresie 9.5 lub później - z dodaną możliwością agregacji tablic:
SELECT name, array_agg(ARRAY[col1, col2] ORDER BY id) AS c_arr
FROM tbl
GROUP BY 1
ORDER BY 1;
Ten sam wynik. Podręcznik:
A więc nie dokładnie to samo, co nasza niestandardowa funkcja agregująca array_agg_mult()
;