Forum: PC-Programmierung MySQL: bei group by Einträge weglassen


von Philipp (Gast)


Lesenswert?

Hallo,

es geht um die Auswertung von gefahrenen Zeiten bei einer 
Rennveranstaltung. Hierbei bekomme ich von der Uhr als Datensatz bei 
jeder Durchfahrt der Lichtschranke die Startnummer und die gefahrene 
Zeit. Diese Daten schreibe ich nun in eine Tabelle:

- ID als Primary Key mit Autoincrement
- Zeit
- Startnummer

Für die Auswertung könnte man nun einfach

select startnr, sum(zeit) as gesamt
from zeit
group by startnr
order by gesamt ASC

abfragen (JOIN mit der Fehlertabelle usw habe ich mal weggelassen).

Das Problem ist nun allerdings, dass die erste Runde nur eine 
Trainingsrunde ist und nicht mit in die Wertung einfließen darf. Diese 
Runde unterscheidet sich von den anderen aber nur anhand der für die 
jeweilige Startnummer kleinsten ID. Die Anzahl der anschließend 
gefahrenen Wertungsläufe ist nicht konstant, darum würde ich das gerne 
so weit offen halten, dass alle weiteren Zeiten danach aufsummiert 
werden.

Ich habe bisher leider keine schöne Lösung gefunden. Das einzige was mir 
einfällt wäre einen eigenen Index pro Startnummer zu vergeben, der beim 
INSERT soetwas wie count(startnr) where startnr = $startnr oder so 
hinzufügt. So könnte man dann nur die Zeilen lesen, deren 
Startnummer-Index größer 0 ist und die Trainingszeiten fallen raus. Das 
macht die Tabelle aber inkonsistent, wenn man Zeiten zwischendurch 
rauslöscht.

Hat jemand hier eine Idee für eine schönere Lösung?

von T.roll (Gast)


Lesenswert?

Mach doch eine zusätzliche Spalte "Training". Die Zeit kannst du so gut 
mit WHERE raushalten. Dann gibt es auch keine Probleme, falls es mal aus 
irgendwelchen Gründen eine zweite Trainingsrunde gibt.

von Luther B. (luther-blissett)


Lesenswert?

Diese Abfrage sollte mehr oder weniger nur die Datensätze rausgeben, zu 
welchen es einen Datensatz mit gleicher startnr und irgendeiner 
niedrigeren ID gibt. Also alles was nicht Testrunde ist:
1
select * 
2
from zeit o 
3
where exists(
4
                select * 
5
                from zeit 
6
                where startnr=o.startnr and id<o.id
7
            );

Kannst du als View speichern und dann darüber gruppieren.

von Nase (Gast)


Lesenswert?

GROUP BY -> HAVING

von Roland P. (pram)


Lesenswert?

Mach eine komplette Abfrage und dann joinst du "SELECT zeit from ... 
where StartNR=o.StartNR Orrder by id limit 1" dazu. Dann hast du die 
Gesamtzeit und die Zeit der 1.Runde in einer Row und kannst sie 
subtrahieren

Gruß
Roland

von Andreas E. (hismastersvoice)


Lesenswert?

Habe gerade keine DB zur Hand, theoretisch könnte aber auch gehen:
1
SELECT SUM(IF(startnr > min(startnr), Zeit, 0)) ... group by startnr

: Bearbeitet durch User
von Philipp (Gast)


Lesenswert?

Vielen Dank für die vielen Hinweise. Ich versuche mal auf die einzelnen 
Antworten einzugehen.

T.roll schrieb:
> Mach doch eine zusätzliche Spalte "Training". Die Zeit kannst du so gut
> mit WHERE raushalten. Dann gibt es auch keine Probleme, falls es mal aus
> irgendwelchen Gründen eine zweite Trainingsrunde gibt.

Das ist leider nicht wirklich praktibel, weil die Autos direkt 
hintereinander fahren. Also sobald der letzte seine Trainingsrunde fährt 
wird hinter ihm schon der mit dem ersten Wertungslauf gestartet. Es kann 
also sein, dass man nur ein 30s Zeitfenster hat um das dann 
umzuschalten. Wenn man da dann nicht aufpasst geht einiges schief. 
Außerdem würde ich so einen Eingriff generell gern vermeiden.



Luther B. schrieb:
> select *
> from zeit o
> where exists(
>                 select *
>                 from zeit
>                 where startnr=o.startnr and id<o.id
>             );

exists() war neu für mich. Dein Vorschlag scheint mein Problem aber 
genau zu lösen :)



Nase schrieb:
> GROUP BY -> HAVING

Hier sehe ich leider keinen Lösungsansatz



Roland P. schrieb:
> Mach eine komplette Abfrage und dann joinst du "SELECT zeit from ...
> where StartNR=o.StartNR Orrder by id limit 1" dazu. Dann hast du die
> Gesamtzeit und die Zeit der 1.Runde in einer Row und kannst sie
> subtrahieren
Die Werte nachher zu subtrahieren fände ich auch eine sehr schöne 
Lösung, weil ich dann in meinem group_concat() alle Zeiten behalten 
könnte und so mit nur einem Query sogar die Trainingszeiten mit ausgeben 
könnte ohne die in die Wertung einfließen zu lassen. Leider begrenzt das 
Limit ja aber die Gesamte Ausgabe und nicht nur die einer spezifischen 
Startnummer oder habe ich dich hier missverstanden?


Andreas E. schrieb:
> Habe gerade keine DB zur Hand, theoretisch könnte aber auch gehen:SELECT
> SUM(IF(startnr > min(startnr), Zeit, 0)) ... group by startnr
Hier ist imho das Problem, dass ich ja nicht die minmale Startnummer 
suche sondern ich jeweils die IDs von gleichen Startnummern vergleichen 
muss. Kann man das evtl. dahingehend formulieren?


Viele Grüße
Philipp

von Roland P. (pram)


Lesenswert?

Andreas Vorschlag könnte auch funktionieren, er hat nur startnr mit id 
verwechselt. In der if Bedingung musst du auf id > min(id) prüfen. Min 
liefert jeweils die kleinste ID je startnr (wegen group by)

von Philipp (Gast)


Lesenswert?

Philipp schrieb:
> Roland P. schrieb:
>> Mach eine komplette Abfrage und dann joinst du "SELECT zeit from ...
>> where StartNR=o.StartNR Orrder by id limit 1" dazu. Dann hast du die
>> Gesamtzeit und die Zeit der 1.Runde in einer Row und kannst sie
>> subtrahieren
> Die Werte nachher zu subtrahieren fände ich auch eine sehr schöne
> Lösung, weil ich dann in meinem group_concat() alle Zeiten behalten
> könnte und so mit nur einem Query sogar die Trainingszeiten mit ausgeben
> könnte ohne die in die Wertung einfließen zu lassen. Leider begrenzt das
> Limit ja aber die Gesamte Ausgabe und nicht nur die einer spezifischen
> Startnummer oder habe ich dich hier missverstanden?

Sorry den JOIN habe ich überlesen

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.