Ho cambiato il nome della colonna group
a grp
perché group
è una parola riservata
in Postgres e in ogni standard SQL e non dovrebbe essere usato come identificatore.
Capisco la tua domanda in questo modo:
Ottieni i due array ordinati in modo identico in modo che la stessa posizione dell'elemento corrisponda alla stessa riga in entrambi gli array.
Utilizza una sottoquery o CTE e ordina le righe prima di aggregare.
SELECT id, array_agg(grp) AS grp, array_agg(dt) AS dt
FROM (
SELECT *
FROM tbl
ORDER BY id, grp, dt
) x
GROUP BY id;
È più veloce piuttosto che utilizzare ORDER BY
clausole nella funzione aggregata
array_agg()
come @Mosty dimostra
(e che esiste da PostgreSQL 9.0). Mosty interpreta anche la tua domanda in modo diverso e usa gli strumenti adeguati per la sua interpretazione.
È ORDER BY
in una cassaforte per sottoquery?
Quindi sì, è sicuro nell'esempio.
Senza sottoquery
Se ne hai veramente necessità una soluzione senza subquery , puoi:
SELECT id
, array_agg(grp ORDER BY grp)
, array_agg(dt ORDER BY grp, dt)
FROM tbl
GROUP BY id;
Nota il ORDER BY grp, dt
. Ordino per dt
oltre a rompere i legami e rendere inequivocabile l'ordinamento. Non necessario per grp
, però.
C'è anche un modo completamente diverso per farlo, con funzioni della finestra :
SELECT DISTINCT ON (id)
id
, array_agg(grp) OVER w AS grp
, array_agg(dt) OVER w AS dt
FROM tbl
WINDOW w AS (PARTITION BY id ORDER BY grp, dt
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
ORDER BY id;
Nota il DISTINCT ON (id)
anziché solo DISTINCT
che produce lo stesso risultato ma si comporta più velocemente di un ordine di grandezza perché non abbiamo bisogno di un ordinamento aggiuntivo.
Ho eseguito alcuni test e questo è quasi veloce quanto le altre due soluzioni. Come previsto, la versione subquery era ancora più veloce. Prova con EXPLAIN ANALYZE
da vedere di persona.