J'ai changé le nom de votre colonne group
à grp
car group
est un mot réservé
dans Postgres et dans tous les standards SQL et ne doit pas être utilisé comme identifiant.
Je comprends votre question comme suit :
Obtenir les deux tableaux triés dans un ordre de tri identique afin que la même position d'élément corresponde à la même ligne dans les deux tableaux.
Utiliser une sous-requête ou CTE et triez les lignes avant de les agréger.
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;
C'est plus rapide que d'utiliser un ORDER BY
clauses dans la fonction d'agrégation
array_agg()
comme @Mosty démontre
(et qui existe depuis PostgreSQL 9.0). Mosty interprète également votre question différemment et utilise les outils appropriés pour son interprétation.
Est ORDER BY
dans un coffre-fort de sous-requêtes ?
Donc oui, c'est sûr dans l'exemple.
Sans sous-requête
Si vous avez vraiment besoin une solution sans sous-requête , vous pouvez :
SELECT id
, array_agg(grp ORDER BY grp)
, array_agg(dt ORDER BY grp, dt)
FROM tbl
GROUP BY id;
Notez le ORDER BY grp, dt
. Je trie par dt
en plus de rompre les liens et de rendre l'ordre de tri sans ambiguïté. Pas nécessaire pour grp
, cependant.
Il existe également une manière complètement différente de procéder, avec les fonctions de fenêtre :
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;
Notez le DISTINCT ON (id)
au lieu de simplement DISTINCT
qui produit le même résultat mais s'exécute plus rapidement d'un ordre de grandeur car nous n'avons pas besoin d'un tri supplémentaire.
J'ai fait quelques tests et c'est presque aussi rapide que les deux autres solutions. Comme prévu, la version de la sous-requête était toujours la plus rapide. Testez avec EXPLAIN ANALYZE
à voir par vous-même.