UNION ALL
Anda dapat melakukan "counter-pivot" dengan UNION ALL
pertama:
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;
Diadaptasi untuk menghasilkan urutan nilai yang Anda minta nanti. Manual:
Penekanan saya yang berani.
LATERAL
subkueri
dengan VALUES
ekspresi
LATERAL
membutuhkan Postgres 9.3 atau lambat.
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;
Hasil yang sama. Hanya perlu satu kali melewati meja.
Fungsi agregat khusus
Atau anda dapat membuat fungsi agregat khusus seperti yang dibahas dalam jawaban terkait ini:
- Memilih data ke dalam Array Postgres
- Apakah ada sesuatu seperti fungsi zip() di PostgreSQL yang menggabungkan dua array?
CREATE AGGREGATE array_agg_mult (anyarray) (
SFUNC = array_cat
, STYPE = anyarray
, INITCOND = '{}'
);
Kemudian Anda dapat:
SELECT name, array_agg_mult(ARRAY[col1, col2] ORDER BY id) AS c_arr
FROM tbl
GROUP BY 1
ORDER BY 1;
Atau, biasanya lebih cepat, meskipun bukan SQL standar:
SELECT name, array_agg_mult(ARRAY[col1, col2]) AS c_arr
FROM (SELECT * FROM tbl ORDER BY name, id) t
GROUP BY 1;
ORDER BY id
. yang ditambahkan (yang dapat ditambahkan ke fungsi agregat tersebut) menjamin hasil yang Anda inginkan:
a | {1,2,3,4}
b | {5,6,7,8}
Atau Anda mungkin tertarik dengan alternatif ini:
SELECT name, array_agg_mult(ARRAY[ARRAY[col1, col2]] ORDER BY id) AS c_arr
FROM tbl
GROUP BY 1
ORDER BY 1;
Yang menghasilkan array 2 dimensi:
a | {{1,2},{3,4}}
b | {{5,6},{7,8}}
Yang terakhir dapat diganti (dan seharusnya, karena lebih cepat!) dengan array_agg()
bawaan di Postgres 9.5 atau lebih baru - dengan kemampuan tambahan untuk menggabungkan array:
SELECT name, array_agg(ARRAY[col1, col2] ORDER BY id) AS c_arr
FROM tbl
GROUP BY 1
ORDER BY 1;
Hasil yang sama. Manual:
Jadi tidak persis sama dengan fungsi agregat kustom kami array_agg_mult()
;