it-swarm.com.de

PostgreSQL MAX und GROUP BY

Ich habe eine Tabelle mit id, year und count.

Ich möchte die MAX(count) für jedes id erhalten und die year behalten, wenn es passiert, also mache ich diese Abfrage:

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

Leider gibt es mir einen Fehler:

FEHLER: Die Spalte "table.year" muss in der GROUP BY-Klausel enthalten sein oder in einer Aggregatfunktion verwendet werden

Also versuche ich:

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

Aber dann macht es nicht MAX(count), es zeigt nur die Tabelle wie sie ist. Ich nehme an, dass beim Gruppieren nach year und id das Maximum für das id des jeweiligen Jahres ermittelt wird.

Wie kann ich diese Abfrage schreiben? Ich möchte die id´s MAX(count) und das Jahr, in dem das passiert, erhalten.

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

oder:

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

oder

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

oder (wie vorher mit einer anderen Notation)

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
41

Die kürzeste (und möglicherweise schnellste) Abfrage wäre mit DISTINCT ON , eine PostgreSQL-Erweiterung der SQL-Standardklausel DISTINCT:

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

Die Zahlen beziehen sich auf die Ordnungszahlen in der Liste SELECT. Sie können die Spaltennamen der Übersichtlichkeit halber buchstabieren:

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

Das Ergebnis wird nach id sortiert, was möglicherweise erwünscht ist oder nicht. Es ist auf jeden Fall besser als "undefiniert".

Es unterbricht auch Verbindungen (wenn mehrere Jahre dieselbe maximale Anzahl haben) auf eine genau definierte Weise: Wählen Sie das früheste Jahr aus. Wenn es Ihnen egal ist, löschen Sie year aus dem ORDER BY. Oder wählen Sie das letzte Jahr mit year DESC.

Weitere Erklärungen, Links, ein Benchmark und möglicherweise schnellere Lösungen in dieser eng verwandten Antwort:

Nebenbei: In einer echten Abfrage würden Sie einige der Spaltennamen nicht verwenden. id ist ein nicht beschreibendes Antimuster für einen Spaltennamen, count ist ein reserviertes Wort in Standard-SQL und eine Aggregatfunktion in Postgres.

58