UNION ALL
Pomocí UNION ALL
byste mohli "protiotočit". první:
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;
Přizpůsobeno k vytvoření pořadí hodnot, které jste později požadovali. Příručka:
Tučné zdůraznění moje.
LATERAL
dílčí dotaz
s VALUES
výraz
LATERAL
vyžaduje Postgres 9.3 nebo později.
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;
Stejný výsledek. Potřebuje pouze jeden průchod přes stůl.
Vlastní agregační funkce
Nebo můžete vytvořit vlastní agregační funkci, jak je popsáno v těchto souvisejících odpovědích:
CREATE AGGREGATE array_agg_mult (anyarray) (
SFUNC = array_cat
, STYPE = anyarray
, INITCOND = '{}'
);
Pak můžete:
SELECT name, array_agg_mult(ARRAY[col1, col2] ORDER BY id) AS c_arr
FROM tbl
GROUP BY 1
ORDER BY 1;
Nebo obvykle rychlejší, i když ne standardní SQL:
SELECT name, array_agg_mult(ARRAY[col1, col2]) AS c_arr
FROM (SELECT * FROM tbl ORDER BY name, id) t
GROUP BY 1;
Přidané ORDER BY id
(které lze k takovým agregačním funkcím připojit) zaručuje požadovaný výsledek:
a | {1,2,3,4}
b | {5,6,7,8}
Nebo by vás mohla zajímat tato alternativa:
SELECT name, array_agg_mult(ARRAY[ARRAY[col1, col2]] ORDER BY id) AS c_arr
FROM tbl
GROUP BY 1
ORDER BY 1;
Což vytváří 2-rozměrná pole:
a | {{1,2},{3,4}}
b | {{5,6},{7,8}}
Poslední lze nahradit (a mělo by být, protože je rychlejší!) vestavěným array_agg()
v Postgres 9.5 nebo novější - s přidanou schopností agregace polí:
SELECT name, array_agg(ARRAY[col1, col2] ORDER BY id) AS c_arr
FROM tbl
GROUP BY 1
ORDER BY 1;
Stejný výsledek. Příručka:
Není to tedy úplně stejné jako naše vlastní agregační funkce array_agg_mult()
;