[MySQL] Gruppierung / Daten bestimmten Alters herauspicken

theHacker

sieht vor lauter Ads den Content nicht mehr
Teammitglied
ID: 69505
L
20 April 2006
22.682
1.316
Moin.

Ich bin gerade am überlegen, wie es das am cleversten löse. PHP möchte ich nicht unbedingt damit bemühen, wenn man es mit einer entsprechenden Query schon in der DB machen kann.

Folgendes:
Ich habe eine Tabelle mit Messpunkten. Jeder Punkt hat einen Typ und einen UNIX-Zeitstempel.
z.B.
Typ 1, Zeit 12234532, Wert 42
Typ 2, Zeit 12234537, Wert 43
Typ 3, Zeit 12234539, Wert 44
Typ 1, Zeit 12245545, Wert 41
Typ 2, Zeit 12235549, Wert 39
...
Ich möchte nun die Werte von allen Typen, die vor -sagen wir- einer Woche waren. Das Problem, wie man sieht, ist der Zeitstempel, da jeder Messpunkt zu einer anderen Zeit genommen wurde, d.h. jeder Typ hat "vor einer Woche" eine andere Zeit gehabt. Es sollten also möglichst die passenden Messpunkte geliefert werden, die am nähsten dran sind.

Wie gehe ich ran ? Spontan würde mir halt einfallen, ich lese mit
Code:
[FONT=Courier New][B][COLOR=#9932cc]SELECT[/COLOR][/B] zeit, wert
[B][COLOR=#9932cc]FROM[/COLOR][/B] tabelle
[B][COLOR=#9932cc]GROUP[/COLOR][/B] [B][COLOR=#9932cc]BY[/COLOR][/B] typ
[B][COLOR=#9932cc]WHERE[/COLOR][/B] zeit>=[B][COLOR=#9932cc]UNIX_TIMESTAMP[/COLOR][/B][COLOR=#9932cc]([/COLOR][COLOR=#9932cc])[/COLOR]-7*24*3600[/FONT]
nur Werte jünger als eine Woche und nimm mit PHP den ersten für jeden Typ raus.

Kann ich das cleverer mit einer Subquery und einem LIMIT machen ?

Und was ich auch gleich nochmal nachfragen muss, weil ich mir da unsicher wäre: Wenn ich von jedem Typ nur den jüngsten Wert haben möchte, also einfach normal gruppiere, muss ich dann ein ORDER BY zeit DESC dazumachen ? Funktioniert das überhaupt und ist das äquivalent zu GROUP BY zeit DESC ?
 
Ich möchte nun die Werte von allen Typen, die vor -sagen wir- einer Woche waren. Das Problem, wie man sieht, ist der Zeitstempel, da jeder Messpunkt zu einer anderen Zeit genommen wurde, d.h. jeder Typ hat "vor einer Woche" eine andere Zeit gehabt. Es sollten also möglichst die passenden Messpunkte geliefert werden, die am nähsten dran sind.

sorry, aber der teil ist irgendwie unklar geschrieben. wenn für die "vor einer woche" immer die anzahl von sekunden aller 7 tage ist, dann würde deine lösung doch genügen. aber was meinst du mit "möglichst nah dran", wo dran?
 
Mmh. So viele Fragen in einem Thema.

Ich glaube deine Abfrage wird nicht funktionieren. Ein "GROUP BY" macht hier keinen Sinn. Du könntest bei deinem Query das "GROUP BY" einfach weglassen und ein "LIMIT 1" ranhängen. Dann hättest du allerdings nur den Wert, der am nächsten an der einen Woche dran ist. "ORDER BY" würde ich auf jeden Fall nutzen.

"GROUP BY" und "ORDER BY" haben eigentlich nix miteinander zu tun. "GROUP BY" brauchst du z.B. wenn du Summen berechnen lassen willst (z.B. SELECT Typ, Sum(Wert) FROM Tabelle GROUP BY Typ). Mit "ORDER BY" bestimmst du die Sortierung der Ergebnisse.

In deinem Fall müßte es "ORDER BY Zeit" heißen. Die Werte sollen ja aufsteigend geordnet sein. "DESC" wäre da auf jeden Fall falsch. Das sortiert absteigend, in dem Fall also die größte Zahl zuerst (was dem neuesten Datum entspricht). Statt "DESC" müßte man dann "ASC" schreiben (für aufsteigend), was man aber weglassen kann, weil es der Standard ist.

Jetzt ist nur dein eigentliches Problem noch nicht gelöst. Und so richtig fällt mir da auch grad nix ein. Wenn du (wie in dem Bsp von dir) nur 3 Typen hast, dann würde ich einfach 3 SQL-Abfragen starten. Das wäre am einfachsten.

Wenn mir noch was besseres einfällt, schreibe ich nochmal.
 
aber was meinst du mit "möglichst nah dran", wo dran?
Die Daten selber werden von einem Cronjob eingetragen und ich weiß nicht wirklich, wann jetzt die Daten kommen. Manchmal kommt ein Messpunkt verspätet rein, manchmal fehlt einer wegen Serverausfall komplett oder so.

Mit "möglichst nah dran" meinte ich, dass ich den Messpunkt selektiere, der dann am nähsten an der wirklichen Zeit "vor einer Woche" lag, obwohl es vor genau einer Woche nicht unbedingt einen Punkt gegeben haben muss.

edit:
Ein "GROUP BY" macht hier keinen Sinn.
[...] "GROUP BY" brauchst du z.B. wenn du Summen berechnen lassen willst [...]
Ähmm.... naja, das stimmt wohl nicht so ganz ;)
Wenn du (wie in dem Bsp von dir) nur 3 Typen hast, dann würde ich einfach 3 SQL-Abfragen starten.
Nur geht es hier nicht um 3 Typen, sondern um n Typen, was sowas natürlich von vornherein ausschließt.
 
Zuletzt bearbeitet:
Mal was grundlegendes: Willst du den Wert, der am nächsten einer Woche entspricht, oder den Wert, der am nächsten einer Woche entspricht, aber kleiner 7 Tage ist (was deinem query entsprechen würde)?
 
ok, dann bin ich raus..

gut möglich, dass sowas auch mit einem einzelnen select möglich ist. grundsätzlich würde ich hier aber zwei selects laufen lassen. einmal DESC und einmal ASC und anschließend die daten mergen. sowas lässt sich natürlich genauso in einem stored procedure einbinden, nur kann das auch eine aufgabe der anwendung sein..

zum GROUP BY bleibt hier als alternative nur noch DISTINCT zu erwähnen.
 
Mal was grundlegendes: Willst du den Wert, der am nächsten einer Woche entspricht, oder den Wert, der am nächsten einer Woche entspricht, aber kleiner 7 Tage ist (was deinem query entsprechen würde)?
Das is mir eigentlich relativ wurscht :mrgreen:
Ich denke mal, die Variante "wenn nix da is, nimm einfach den nächst älteren" gefällt mir besser.

Bei meinem Query ist es halt noch so, dass ich dann noch alle Werte mit abfrage, die noch jünger sind, obwohl ich diese nicht brauch.
Ich bräuchte also etwas in der Art "GROUP BY typ LIMIT 1 EVERY typ", dass ich nur einen Datensatz pro Typ bekomme.

GROUP BY fasst ja die Datensätze eines Typs zusammen, allerdings bin ich mir dann nicht sicher, ob ich dann den Datensatz mit der richtigen Zeit bekomme :think:
zum GROUP BY bleibt hier als alternative nur noch DISTINCT zu erwähnen.
Stimmt, das is auch noch'n Ansatz.
Allerdings wär ich mir auch hier wieder unsicher, ob ich dann die richtige Zeit hab bzw. wie ich das richtig einsetzt. Das muss ich morgen mal genauer probieren.
 
wie wärs mit:
Code:
[FONT=Courier New][B][COLOR=#9932cc]SELECT[/COLOR][/B] zeit, wert
[B][COLOR=#9932cc]FROM[/COLOR][/B] tabelle
[B][COLOR=#9932cc]ORDER[/COLOR][/B] [B][COLOR=#9932cc]BY[/COLOR][/B] zeit DESC
[B][COLOR=#9932cc]GROUP[/COLOR][/B] [B][COLOR=#9932cc]BY[/COLOR][/B] typ
[B][COLOR=#9932cc]WHERE[/COLOR][/B] zeit>=[B][COLOR=#9932cc]UNIX_TIMESTAMP[/COLOR][/B][COLOR=#9932cc]([/COLOR][COLOR=#9932cc])[/COLOR]-7*24*3600[/FONT]
:?:
 
Ne "saubere" Lösung mit einem Query fällt mir dazu nicht ein. Aber man kann sich das verhalten von GROUP BY von Mysql zu nutze machen, dass immer der erste Datensatz genommen wird.

PHP:
SELECT
	messwerte_filter.typ,
	messwerte_filter.zeit,
	messwerte_filter.wert
FROM
	(
		SELECT
			messwerte.typ,
			messwerte.zeit,
			messwerte.wert
		FROM
			messwerte
		WHERE
			zeit < als letzte woche /*eventuell noch begrenzen auf eine zeitspanne, man brauch nicht 100jahre zurück schauen*/
		ORDER BY
			zeit DESC
	) AS messwerte_filter
GROUP BY
	messwerte_filter.typ
 
laut MySQL.org:
MySQL erweitert die GROUP BY-Klausel dahingehend, dass Sie ASC und DESC auch nach den in der Klausel benannten Spalten angeben können:
daher würde ich sagen das;
Code:
[FONT=Courier New][B][COLOR=#9932cc]SELECT[/COLOR][/B] zeit, wert [B][COLOR=#9932cc]
FROM[/COLOR][/B] tabelle 
[B][COLOR=#9932cc]GROUP[/COLOR][/B] [B][COLOR=#9932cc]BY[/COLOR][/B] typ [B][COLOR=DarkOrchid]DESC[/COLOR][/B]
[B][COLOR=#9932cc]WHERE[/COLOR][/B] zeit>=[B][COLOR=#9932cc]UNIX_TIMESTAMP[/COLOR][/B][COLOR=#9932cc]([/COLOR][COLOR=#9932cc])[/COLOR]-7*24*3600[/FONT]
seinen dienst tun sollte.

gruß,
whirpool
 
laut MySQL.org:daher würde ich sagen das;
Code:
[FONT=Courier New][B][COLOR=#9932cc]SELECT[/COLOR][/B] zeit, wert [B][COLOR=#9932cc]
FROM[/COLOR][/B] tabelle 
[B][COLOR=#9932cc]GROUP[/COLOR][/B] [B][COLOR=#9932cc]BY[/COLOR][/B] typ [B][COLOR=DarkOrchid]DESC[/COLOR][/B]
[B][COLOR=#9932cc]WHERE[/COLOR][/B] zeit>=[B][COLOR=#9932cc]UNIX_TIMESTAMP[/COLOR][/B][COLOR=#9932cc]([/COLOR][COLOR=#9932cc])[/COLOR]-7*24*3600[/FONT]
seinen dienst tun sollte.

gruß,
whirpool

Damit sortierst du nach Typ...
 
Um das Problem mit den ungenauen Timestamps zu lösen, könntest du evtl. nach DATE(FROM_UNIXTIME(zeit)) gruppieren.

Allerdings bin ich mir auch noch nicht 100% sicher, was du eigentlich willst^^ ;)