2012-11-10 7 views
18

Mam tabelę z id, year i count.PostgreSQL MAX i GROUP BY

Chcę uzyskać MAX(count) dla każdego id i utrzymać year kiedy to się dzieje, więc robię to zapytanie:

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

Niestety, to wyskakuje mi błąd:

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

So Próbuję:

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

Ale potem d nie robi się MAX(count), po prostu pokazuje tabelę taką jaka jest. Przypuszczam, że podczas grupowania przez year i id, uzyskuje maksymalną wartość dla id tego konkretnego roku.

Jak mogę napisać to zapytanie? Chcę uzyskać id's MAX(count) i rok, w którym to się stanie.

+1

jeśli {id, year} są unikalne, 'max (rzecz)' jest tym samym co 'thing'.Zauważ też, że "liczba" jest słowem kluczowym (i rokiem również w niektórych dialektach, IIRC). – wildplasser

+0

W jakim roku chciałbyś się znaleźć z każdym identyfikatorem? Nie ma "roku", jest ich więcej niż jeden, może chcesz "MAX (rok)"? – mata

+0

Tak, są wyjątkowe, więc dostaję rzeczy. Chcę uzyskać ids MAX (rzecz), a także zobaczyć, w którym roku się to stanie. (Nie pisałem, liczę w moim kodzie, tylko przykład) –

Odpowiedz

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

czyli

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); 

lub

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 

lub (taki sam jak poprzedni z innym notacji)

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: Wszystkie te zapytania zwracają wiele wartości na id, gdy wiele lat dzieli się maksimum liczyć. Będziesz musiał zdefiniować, co chcesz w tym powszechnym przypadku. Pokaż wszystko? Wybierz jedno? Najnowsze/najwcześniej/cokolwiek? Pokaż listę lat w jednej kolumnie? –

+0

@a_horse_with_no_name Czy możesz wyjaśnić plusy i minusy każdego z tych zapytań? – Stratus3D

36

Najkrótsza (i możliwie najszybciej) zapytania będzie z DISTINCT ON , Rozszerzenie PostgreSQL z SQL standardowej DISTINCT klauzuli:

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

Liczby są porządkowe pozycji na liście SELECT można przeliterować też:

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

Rezultatem jest sortowana według id, które mogą ale nie muszą być mile widziane. W każdym razie jest lepsze niż "niezdefiniowane".

Łamie również więzi (gdy wiele lat dzieli tę samą maksymalną liczbę) w dobrze określony sposób: wybierz najwcześniejszy rok. Jeśli Cię to nie interesuje, upuść year z ORDER BY. Lub wybierz ostatni rok z year DESC.

więcej wyjaśnień, linki, benchmark an ewentualnie szybsze rozwiązania w tym ściśle związane odpowiedź:

marginesie: W prawdziwym życiu zapytania, nie będzie korzystać z niektórych nazwy kolumn. id to nie opisowy wzorzec dla nazwy kolumny, count to funkcja agregująca w PostgreSQL.