2011-09-30 4 views
10

J'ai une table simple avec un oid unit_id, un horodatage, un diag bytea. La clé primaire est une combinaison de time et unit_id.Postgres sélectionner toutes les colonnes mais grouper par une colonne

L'idée derrière cette requête est d'obtenir la dernière ligne (le plus grand horodatage) pour chaque identifiant unique. Cependant, les lignes pour chaque unité_id avec la dernière heure ne sont pas toujours retournées.

Je veux vraiment grouper juste par l'unit_id, mais postgres me fait utiliser diag aussi, puisque je choisis cela.

SELECT DISTINCT ON(unit_id) max(time) as time, diag, unit_id 
FROM diagnostics.unit_diag_history 
GROUP BY unit_id, diag 

Répondre

14

Chaque fois que vous commencez à penser que vous voulez un groupe localisé PAR vous devriez commencer à penser à la place window functions.

Je pense que vous êtes après quelque chose comme ceci:

select unit_id, time, diag 
from (
    select unit_id, time, diag, 
      rank() over (partition by unit_id order by time desc) as rank 
    from diagnostics.unit_diag_history 
) as dt 
where rank = 1 

Vous pouvez ajouter quelque chose à l'ORDER BY pour briser systématiquement des liens aussi bien, mais qui ne modifierait pas la technique globale.

+0

Pouvons-nous le faire sans utiliser le sous-select? – metdos

+0

@metdos: Je ne peux pas penser à quoi que ce soit du haut de la tête, mais il pourrait y avoir un moyen. Quel est le problème avec les tables dérivées? –

9

Vous pouvez joindre la sélection groupée avec la table d'origine:

SELECT d.time, d.diag, d.unit_id 
FROM(
    SELECT unit_id, max(time) as max_time 
    FROM diagnostics.unit_diag_history 
    GROUP BY unit_id 
) s JOIN diagnostics.unit_diag_history d 
ON s.unit_id = d.unit_id AND s.max_time = d.time 
+0

C'est la seule réponse que j'ai trouvé dans plusieurs jours de Google qui m'a aidé de quelque façon que ce soit (venant de MySQL). – Adrian

Questions connexes