sql >> Base de Datos >  >> RDS >> PostgreSQL

Unir matrices dentro de la cláusula group by

UNION ALL

Podrías "contra-pivotar" con UNION ALL primero:

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;

Adaptado para producir el orden de valores que solicitó más tarde. El manual:

Énfasis en negrita mío.

LATERAL subconsulta con VALUES expresión

LATERAL requiere Postgres 9.3 o posterior.

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;

Mismo resultado. Solo necesita una sola pasada sobre la mesa.

Función agregada personalizada

O podría crear una función agregada personalizada como la discutida en estas respuestas relacionadas:

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

Entonces puedes:

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

O, por lo general, más rápido, aunque no SQL estándar:

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

El ORDER BY id agregado (que se puede agregar a dichas funciones agregadas) garantiza el resultado deseado:

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

O quizás te interese esta alternativa:

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

Lo que produce arreglos bidimensionales:

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

El último puede ser reemplazado (¡y debería serlo, ya que es más rápido!) con el array_agg() incorporado en Postgres 9.5 o posterior, con su capacidad adicional de agregar matrices:

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

Mismo resultado. El manual:

Así que no es exactamente lo mismo que nuestra función agregada personalizada array_agg_mult();