problem mit "select max()"

Guten Morgen,

ich komme irgendwie nicht weiter.
Ich habe folgende tabelle

datum | typ

in dieser tabelle stehen werte wie z.b.


15.01.2007 15:00:00 | 1
15.01.2007 17:00:00 | 2
15.01.2007 18:00:00 | 1
16.01.2007 12:00:00 | 2
16.01.2007 13:00:00 | 2

ich möchte jetzt, dass mir jeweils das größte datum des tages für jeden typ ausgegeben wird.
also in diesem besipiel:

15.01.2007 18:00:00 | 1
15.01.2007 17:00:00 | 2
16.01.2007 13:00:00 | 2

ich habe schon alles mögliche mit max() und group by probiert aber dabei kam nie das raus was ich wollte.

kann mir einer von euch helfen?

Danke für eure Mühe!
Crypi



test=*# select * from foo;
            d            | val
-------------------------+-----
 15.01.2007 15:00:00 CET |   1
 15.01.2007 17:00:00 CET |   2
 15.01.2007 18:00:00 CET |   1
 16.01.2007 12:00:00 CET |   2
 16.01.2007 13:00:00 CET |   2
(5 rows)

test=*# select val, d::date, max(d) from foo group by 1,2 order by 3;
 val |     d      |           max
-----+------------+-------------------------
   2 | 15.01.2007 | 15.01.2007 17:00:00 CET
   1 | 15.01.2007 | 15.01.2007 18:00:00 CET
   2 | 16.01.2007 | 16.01.2007 13:00:00 CET
(3 rows)

Andreas

was es nicht alles gibt. ich werd das gleich mal ausprobieren!

Crypi

Guten Morgen,

das funktioniert ja so wirklich schon klasse, jetzt habe ich nur noch eine weitere Frage.

Jetzt sollen nur noch die datensätze selektiert werden, die die späteste uhrzeit des tages und val=2 haben.
die einzigen lösungen die mir eingefallen sind, beinhalten ein exists oder eine weitere select als unterabfrage.
das dauert dann bei 80000 datensätzen nur leider etwas lang.
gibts eine möglichkeit das irgendwie anders zu lösen?

so dass dann nur noch

2 | 16.01.2007 | 16.01.2007 13:00:00

ausgegeben wird.

Crypi



test=*# select * from foo;
           d            | val
------------------------+-----
 2007-01-15 15:00:00+01 |   1
 2007-01-15 17:00:00+01 |   2
 2007-01-15 18:00:00+01 |   1
 2007-01-16 12:00:00+01 |   2
 2007-01-16 13:00:00+01 |   2
(5 rows)

test=*# select max(d),val, d::date from foo where val=2 group by val,d::date;
          max           | val |     d
------------------------+-----+------------
 2007-01-16 13:00:00+01 |   2 | 2007-01-16
 2007-01-15 17:00:00+01 |   2 | 2007-01-15
(2 rows)

test=*#

Falls das Performance-Probleme gibt, dann schaue ins EXPLAIN, warum. Indexe auf val und d sollten aber der Sache dienlich sein.


Andreas

Danke für die schnelle Antwort!

Deine Query trifft nicht genau das was ich meine.

er soll den datensatz ja nur ausgeben, wenn es keinen eintrag mit einer späteren zeit am gleichen tag und val=1 gibt. das heißt den datensatz vom 15.01.2007 sollte er nicht mit ausgeben.

mit dem index und dem explain werde ich mich mal beschäftigen.

aber fällt dir denn eine lösung ein, wie man die abfrage anders gestalten könnte und das richtige ergebnis bekommt?

edit:
eine lösung wäre ja:

select a.val, a.d::date, max(a.d) from foo as a where val=2 and not exists(select datum from foo where datum::date=a.datum::date and a.datum<datum) group by 1,2 order by 3;
wie bekomme ich das mit einem index performanter? es gibt da ja so einige möglichkeiten und ich kenne mich damit nicht aus.


Crypi

Schnellschuß:

test=*# select max(d) as d,val  from foo where (d,val) in (select max(d),2 from foo group by val) group by val,d::date;
           d            | val
------------------------+-----
 2007-01-16 13:00:00+01 |   2
(1 row)

Andreas

Hi,

ich hab noch eine frage zum “group by”.

Ich will jetzt zusätzlich zu den Feldern die im “group by” auftauchen noch einige andere selektieren. Wie bekomme ich das denn hin? einfach ins select schreiben geht ja nicht.
Ich möchte mit einem Left Join noch andere daten erfassen, wenn ich die entsprechenden Felder jetzt allerdings in die group-klausel übernehme klappt das alles nicht mehr. dann bekomme ich andere ergebnisse.

Wie muss ich das denn machen?

Beispiel:

select max(a.d),a.val, a.d::date,b.name,b.vorname from foo as a
LEFT JOIN foo2 as b
on (a.laufendenummer=b.laufendenummer_a)
where val=2 group by val,d::date;

so gehts nicht…

Crypi

Stimmt. Alle Spalten, die nicht aggregiert sind, müssen in der GROUP BY - Klausel stehen.

Andreas

hmm…

und wie könnte ich es dann hinbekommen, dass ich immer den kompletten datensatz mit der größten uhrzeit für jeden tag finde?

Okay, noch mal von vorne:

test=*# select * from foo;
           ts           | val | name  | id
------------------------+-----+-------+----
 2007-01-01 10:00:00+01 |   1 | test1 |  1
 2007-01-01 11:00:00+01 |   2 | test2 |  2
 2007-01-02 12:00:00+01 |   3 | test3 |  3
(3 rows)

Dich interessiert Datensatz 2 und 3:

test=*# select distinct a.* from foo a, foo b where (a.ts,a.ts::date) in (select max(ts), ts::date from foo group by ts::date);
           ts           | val | name  | id
------------------------+-----+-------+----
 2007-01-01 11:00:00+01 |   2 | test2 |  2
 2007-01-02 12:00:00+01 |   3 | test3 |  3
(2 rows)

Ist allerdings bei großen Tabellen a bissl ungünstig, weil ohne distinct das erst mal ein Kreuzprodukt ist:

test=*# select a.* from foo a, foo b where (a.ts,a.ts::date) in (select max(ts), ts::date from foo group by ts::date);
           ts           | val | name  | id
------------------------+-----+-------+----
 2007-01-01 11:00:00+01 |   2 | test2 |  2
 2007-01-01 11:00:00+01 |   2 | test2 |  2
 2007-01-01 11:00:00+01 |   2 | test2 |  2
 2007-01-02 12:00:00+01 |   3 | test3 |  3
 2007-01-02 12:00:00+01 |   3 | test3 |  3
 2007-01-02 12:00:00+01 |   3 | test3 |  3
(6 rows)

Mir fällt aber grad nix besseres ein, muß noch mal weg…


Andreas

So, schnell noch dies:

test=*# select * from foo;
           ts           | val | name
------------------------+-----+-------
 2007-01-01 10:00:00+01 |   1 | name1
 2007-01-01 12:00:00+01 |   2 | name2
 2007-01-01 18:00:00+01 |   3 | name3
 2007-01-02 09:00:00+01 |   4 | name4
 2007-01-04 09:00:00+01 |   5 | name5
 2007-01-04 10:00:00+01 |   6 | name6
(6 rows)

Den letzten Record pro Tag bekommst Du nun so:

test=*# select a.ts, a.val, a.name from foo a join (select distinct ts::date as datum, max(ts) as ts from foo group by 1) as b on b.ts=a.ts;
           ts           | val | name
------------------------+-----+-------
 2007-01-01 18:00:00+01 |   3 | name3
 2007-01-02 09:00:00+01 |   4 | name4
 2007-01-04 10:00:00+01 |   6 | name6
(3 rows)

Andreas

Danke für deine Hilfe und Geduld!


Ich glaub jetzt hab ichs :slight_smile:

Crypi