2012-11-10 21 views
18

Ho una tabella con id, year e count.PostgreSQL MAX e GROUP BY

voglio ottenere il MAX(count) per ogni id e mantenere il year quando accade, quindi faccio questa domanda:

SELECT id, year, MAX(count) 
FROM table 
GROUP BY id; 

Purtroppo, mi dà un errore:

ERROR: column "table.year" must appear in the GROUP BY clause or be used in an aggregate function

Così Provo:

SELECT id, year, MAX(count) 
FROM table 
GROUP BY id, year; 

Ma poi, d Non deve fare MAX(count), mostra solo la tabella così com'è. Suppongo che quando si raggruppa per year e id, si ottiene il massimo per lo id di quell'anno specifico.

Quindi, come posso scrivere quella domanda? Voglio ottenere lo e l'anno in cui ciò accade.

+1

se {id, anno} sono univoci, 'max (cosa)' è uguale a 'cosa'.Nota che "contare" è una parola chiave, (e anche l'anno in alcuni dialetti, IIRC) – wildplasser

+0

Che anno vuoi ottenere con ogni ID? Non c'è un "anno", ce ne sono più di uno, forse vuoi 'MAX (anno)'? – mata

+0

Sì, sono unici quindi ho una cosa. Voglio ottenere gli ID MAX (cosa) e anche, vedere in che anno accade. (Non stavo scrivendo conto nel mio codice, solo un esempio) –

risposta

21
select * 
from (
    select id, 
     year, 
     thing, 
     max(thing) over (partition by id) as max_thing 
    from the_table 
) t 
where thing = max_thing 

o:

select t1.id, 
     t1.year, 
     t1.thing 
from the_table t1 
where t1.thing = (select max(t2.thing) 
        from the_table t2 
        where t2.id = t1.id); 

o

select t1.id, 
     t1.year, 
     t1.thing 
from the_table t1 
    join ( 
    select id, max(t2.thing) as max_thing 
    from the_table t2 
    group by id 
) t on t.id = t1.id and t.max_thing = t1.thing 

o (come la precedente con una notazione differente)

with max_stuff as (
    select id, max(t2.thing) as max_thing 
    from the_table t2 
    group by id 
) 
select t1.id, 
     t1.year, 
     t1.thing 
from the_table t1 
    join max_stuff t2 
    on t1.id = t2.id 
    and t1.thing = t2.max_thing 
+0

@ user1504577: tutte queste query restituiscono più valori per ID quando più anni condividono il massimo contare. Dovresti definire ciò che vuoi in questo caso comune. Mostra tutto? Sceglierne uno? L'ultima/prima/qualunque? Mostra un elenco di anni in una colonna? –

+0

@a_horse_with_no_name puoi spiegare i pro e i contro di ciascuna di queste query? – Stratus3D

36

La query più breve (e possibilmente più veloce) sarebbe con DISTINCT ON , Un'estensione di PostgreSQL dello standard DISTINCT clausola di SQL:

SELECT DISTINCT ON (1) 
     id, count, year 
FROM tbl 
ORDER BY 1, 2 DESC, 3; 

I numeri sono posizioni ordinali nella lista SELECT, è possibile inserirlo fuori, troppo:

SELECT DISTINCT ON (id) 
     id, count, year 
FROM tbl 
ORDER BY id, count DESC, year; 

Il risultato è ordinato da id, che può o non può essere benvenuto. È meglio di "non definito" in ogni caso.

Rompe anche i legami (se più anni condividono lo stesso conteggio massimo) in un modo ben definito: scegli l'anno più recente. Se non ti interessa, elimina year dal ORDER BY. Oppure scegli l'ultimo anno con year DESC.

Più spiegazione, link, un punto di riferimento una soluzione possibilmente più veloci in questa risposta strettamente correlati:

parte: In una vera e propria domanda di vita, non si utilizzare alcune delle nomi di colonne. id è un anti-pattern non descrittivo per il nome di una colonna, count è un reserved word in standard SQL e count() una funzione di aggregazione in Postgres.