MySQL Tabelle - Zeitangaben
Moinsen,
ich möchte Werte in eine MySQL Tabelle eingeben, die einer Zeitangabe entsprechen. Welchen Typ muss ich für diesen Wert eintragen?
So kommt der Wert aus einer Textdatei:
1:45.661
So soll er dann in der Tabelle stehen:
1:45.661
Die Tabelle sollte (u.a.) mit diesem Wert sortierbar sein.
z.B.
1:45.661
1:45.662
1:45.663
1:45.664
1:55.661
Wer kann mir da einen Tipp geben?
MfG
jhe
ich möchte Werte in eine MySQL Tabelle eingeben, die einer Zeitangabe entsprechen. Welchen Typ muss ich für diesen Wert eintragen?
So kommt der Wert aus einer Textdatei:
1:45.661
So soll er dann in der Tabelle stehen:
1:45.661
Die Tabelle sollte (u.a.) mit diesem Wert sortierbar sein.
z.B.
1:45.661
1:45.662
1:45.663
1:45.664
1:55.661
Wer kann mir da einen Tipp geben?
MfG
jhe
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 193209
Url: https://administrator.de/forum/mysql-tabelle-zeitangaben-193209.html
Ausgedruckt am: 23.12.2024 um 04:12 Uhr
51 Kommentare
Neuester Kommentar
Hallo jhe,
einfach mal String (Text) nehmen, da es keinen Zahlentyp gibt, der den Doppelpunkt abbilden kann
LG
einfach mal String (Text) nehmen, da es keinen Zahlentyp gibt, der den Doppelpunkt abbilden kann
LG
Hallo,
1. auf garkeinen Fall text nehmen
2. bitte nicht als varchar abspeichern
Wenn die Zahl hinter de Punkt Millisekunden sind, dann auch komplett als Millisekunden abspeichern. Ist doch bei einem select schnell sortiert und das DBMS hat am wenigstens arbeit.
Ansonsten ist diese Doku sinnvoll: http://dev.mysql.com/doc/refman/5.1/de/storage-requirements.html
Da kannst Du dann auch den passenden Zahlentyp auswählen.
Gruß
Heiko
1. auf garkeinen Fall text nehmen
2. bitte nicht als varchar abspeichern
Wenn die Zahl hinter de Punkt Millisekunden sind, dann auch komplett als Millisekunden abspeichern. Ist doch bei einem select schnell sortiert und das DBMS hat am wenigstens arbeit.
Ansonsten ist diese Doku sinnvoll: http://dev.mysql.com/doc/refman/5.1/de/storage-requirements.html
Da kannst Du dann auch den passenden Zahlentyp auswählen.
Gruß
Heiko
Moin jhe1960,
in diesem Fall liegen die eher verhaltenen Antworten auf deine Frage auch daran, dass du dem (eigentlich recht brauchbaren) mySQL nun unbeabsichtigt etwas in den Schritt gefasst hast.
Die Krux ist
- du könntest diese Strings im Format "1:55.661" (Minuten:Sekunden.ZehntelHundertstelTausendstel)" zwar als Varchar() speichern inklusive der Doppelpunkte und dann zwar nicht damit rechnen, aber zumindest auf-/absteigend sortieren, wenn denn alle Datensätze nur einstellige Sekundenwerte haben. So etwas ist eine Rahmenbedingung, die in der Praxis niemand garantieren würde.
- immer "richtig" sortieren könntest du natürlich Time/Datetime-Werte. Leider leider leider kann mySQL zwar bei der Datums-/Zeitarithmetik mit Millisekunden rechnen, aber (nich' lachen jezz!) in MySQL werden Millisekunden bei Time/Timestamp-Datentypen nicht gespeichert.
- drittens könntest du die Werte als numerischen Wert speichern (z.B.als Integer), aber dann musst du es halt umrechnen. Im Beispiel "1:55.661" müsstest du also als Integer-Millisekundenwert errechnen und speichern "(1 Minute in Millisekunden) plus 55661 Millsekunden".
- Viertens könntest du auch die "1:55.661"etc-Werte in zwei Datenfeldern speichern, nämlich in einem Time/Timestampfeld (nur mit Sekundengenauigkeit) und den fractional-Anteil, die Millisekunden in einem Extra-Integer-Millisekundenfeld.
Ich würde vermutlich die vierte Variante wählen, auch wenn die noch nicht genannt wurde.
Im (für begrenzt optimistische Datenschaufler wie mich) absolut realitätsfernen Szenario "alle Zeitwerte haben IMMER dieselbe Textlänge == Länge("1:55:661")== 8 Zeichen und es wird NIE NIE NIE eine Ausnahme davon geben UND ich werde NIE NIE NIE mit den Zeiten rechnen wollen (z.B. Durchschnittswerte pro Gruppe)"
-> dann nimm Varchar und einen stumpfen Textvergleich für die Sortierung.
Grüße
Biber
in diesem Fall liegen die eher verhaltenen Antworten auf deine Frage auch daran, dass du dem (eigentlich recht brauchbaren) mySQL nun unbeabsichtigt etwas in den Schritt gefasst hast.
Die Krux ist
- du könntest diese Strings im Format "1:55.661" (Minuten:Sekunden.ZehntelHundertstelTausendstel)" zwar als Varchar() speichern inklusive der Doppelpunkte und dann zwar nicht damit rechnen, aber zumindest auf-/absteigend sortieren, wenn denn alle Datensätze nur einstellige Sekundenwerte haben. So etwas ist eine Rahmenbedingung, die in der Praxis niemand garantieren würde.
- immer "richtig" sortieren könntest du natürlich Time/Datetime-Werte. Leider leider leider kann mySQL zwar bei der Datums-/Zeitarithmetik mit Millisekunden rechnen, aber (nich' lachen jezz!) in MySQL werden Millisekunden bei Time/Timestamp-Datentypen nicht gespeichert.
- drittens könntest du die Werte als numerischen Wert speichern (z.B.als Integer), aber dann musst du es halt umrechnen. Im Beispiel "1:55.661" müsstest du also als Integer-Millisekundenwert errechnen und speichern "(1 Minute in Millisekunden) plus 55661 Millsekunden".
- Viertens könntest du auch die "1:55.661"etc-Werte in zwei Datenfeldern speichern, nämlich in einem Time/Timestampfeld (nur mit Sekundengenauigkeit) und den fractional-Anteil, die Millisekunden in einem Extra-Integer-Millisekundenfeld.
Ich würde vermutlich die vierte Variante wählen, auch wenn die noch nicht genannt wurde.
Im (für begrenzt optimistische Datenschaufler wie mich) absolut realitätsfernen Szenario "alle Zeitwerte haben IMMER dieselbe Textlänge == Länge("1:55:661")== 8 Zeichen und es wird NIE NIE NIE eine Ausnahme davon geben UND ich werde NIE NIE NIE mit den Zeiten rechnen wollen (z.B. Durchschnittswerte pro Gruppe)"
-> dann nimm Varchar und einen stumpfen Textvergleich für die Sortierung.
Grüße
Biber
Moin Jürgen,
versuch es so:
Mimik: ich hole mir (unter dem Aliasnamen "Top10Times") die 10 kleinsten Zeiten für die TrackId 84 und SessionId 1 oder 2 je Fahrer.
Und zusätzlich die ID dieses Datensatzes.
Über die Tracking.ID komme ich wieder an die Detaildaten Minutes, Seconds etc.
Die IMHO unnötigerweise verjointen Tabellen, aus denen kene Infos gebraucht werden, die habe ich auskommentiert.
Ungetestet.
Grüße
Biber
versuch es so:
SELECT Top10Times.time
, d.Name AS Fahrer
, t.Minutes AS Minutes
, t.Seconds AS Seconds
, t.Milliseconds AS Milliseconds
FROM (select t.driverid
, min ( ( t.Minutes *60) + ( t.Seconds ) + ( t.Milliseconds /1000 )) AS time
, min(t.id) as id
from trackerneu.tracking t
Where t.TrackID =84
and t.sessionId in (2, 3)
group by driverId
LIMIT 0 , 10
) top10times
-- trackerneu.tracks tx
, trackerneu.tracking t
, trackerneu.driver d
--, trackerneu.session s
--, trackerneu.vehicle v
WHERE t.ID =Top10Times.Id
AND t.DriverID = d.ID
Mimik: ich hole mir (unter dem Aliasnamen "Top10Times") die 10 kleinsten Zeiten für die TrackId 84 und SessionId 1 oder 2 je Fahrer.
Und zusätzlich die ID dieses Datensatzes.
Über die Tracking.ID komme ich wieder an die Detaildaten Minutes, Seconds etc.
Die IMHO unnötigerweise verjointen Tabellen, aus denen kene Infos gebraucht werden, die habe ich auskommentiert.
Ungetestet.
Grüße
Biber
Moin Jürgen,
die einzelnen Buchstaben hinter den Tabellennamen sind so genannte Aliasnamen,
Bedeutet, dass ich (s.o.) alle Felder der Tabelle trackerneu.tracking alias t ansprechen kann als t.id, t.minutes etc.
Hat 27 Vorteile.
Die 3 wichtigsten:
- Es macht das Statement lesbar und wartbar
- ich kann auch ohne Syntaxerror reservierte Worte als Feldnamen verwenden (minutes, seconds, user, alter)
und identische Spaltennamen in mehreren Tabellen ansprechen Denn ein t.id ist eindeutig ein Verweis auf EIN Feld in EINER Tabelle mit dem Alias t.
- Wenn sowohl die Tabellen einen Alias haben wie auch die Bedingungen im WHERE wie auch die Felder im SELECT-Teil, dann siehst du schnell, ob du alle Tabellen überhaupt benötigst (s.o). In deinem Select war z.B. die Tabelle Vehicle mit angegeben, aber weder mit einer anderen Tabelle verjoined noch wurde ein Feld von Vehicle angezeigt,
Grüße
Biber
Zu deinem P.S.
Ja, kann beim Copy&Paste immer sein.
Teste zuerst, ob hierbei etwas herauskommt:
B.
die einzelnen Buchstaben hinter den Tabellennamen sind so genannte Aliasnamen,
Bedeutet, dass ich (s.o.) alle Felder der Tabelle trackerneu.tracking alias t ansprechen kann als t.id, t.minutes etc.
Hat 27 Vorteile.
Die 3 wichtigsten:
- Es macht das Statement lesbar und wartbar
- ich kann auch ohne Syntaxerror reservierte Worte als Feldnamen verwenden (minutes, seconds, user, alter)
und identische Spaltennamen in mehreren Tabellen ansprechen Denn ein t.id ist eindeutig ein Verweis auf EIN Feld in EINER Tabelle mit dem Alias t.
- Wenn sowohl die Tabellen einen Alias haben wie auch die Bedingungen im WHERE wie auch die Felder im SELECT-Teil, dann siehst du schnell, ob du alle Tabellen überhaupt benötigst (s.o). In deinem Select war z.B. die Tabelle Vehicle mit angegeben, aber weder mit einer anderen Tabelle verjoined noch wurde ein Feld von Vehicle angezeigt,
Grüße
Biber
Zu deinem P.S.
Ja, kann beim Copy&Paste immer sein.
Teste zuerst, ob hierbei etwas herauskommt:
Select *
FROM (select t.driverid
, min ( ( t.Minutes *60) + ( t.Seconds ) + ( t.Milliseconds /1000 )) AS time
, min(t.id) as id
from trackerneu.tracking t
Where t.TrackID =84
and t.sessionId in (2, 3)
group by driverId
LIMIT 0 , 10
) top10times
Moin Jürgen,
okay, machen wir mit dem Komplett-Statement weiter.
Denn etwas besser bekommen wir es noch hin.
Grüße
Biber
okay, machen wir mit dem Komplett-Statement weiter.
Denn etwas besser bekommen wir es noch hin.
SELECT Top10Times.time
, d.Name AS Fahrer
, t.Minutes AS Minutes
, t.Seconds AS Seconds
, t.Milliseconds AS Milliseconds
FROM (select t.driverid -- gruppiert nach DriverId=Fahrer..
, t.trackId -- ...und nach Rennstrecke
, min ( ( t.Minutes *60) + ( t.Seconds ) + ( t.Milliseconds /1000 )) AS time
, min(t.id) as id
from trackerneu.tracking t
Where t.sessionId in (2, 3) -- das gilt für alle Rennstrecken (?)
group by t.driverId, t.TrackID
) top10times
-- trackerneu.tracks tx
, trackerneu.tracking t
, trackerneu.driver d
--, trackerneu.session s
--, trackerneu.vehicle v
WHERE t.ID =Top10Times.Id
AND t.TrackID =84
-- auf eine Rennstrecke filtern erst hier in der WHERE-Clause,
-- wo es auch jeder sucht und erwartet
AND t.DriverID = d.ID
ORDER BY 1 DESC
LIMIT 0 , 10
Grüße
Biber
Moin Jürgen,
ja nee...is' klar..
a) weil ich blöd bin
b) und weil heute Montach ist..
STREICHE:
SETZE: :
Sorry, eigentlich fasse ich montachmorgens auch nichts mit mehr als drei Zeilen an...
Grüße
Biber
ja nee...is' klar..
a) weil ich blöd bin
b) und weil heute Montach ist..
STREICHE:
group by t.driverId, t.TrackID
--> damit bekommen wir die jeweils 10 schnellsten Fahrten jedes Fahrers über alle StreckenSETZE: :
group by t.TrackID, t.driverID
--> damit bekommen wir die jeweils 10 schnellsten Fahrer je Strecke, und die wollen wirSorry, eigentlich fasse ich montachmorgens auch nichts mit mehr als drei Zeilen an...
Grüße
Biber
Moin Jürgen,
na okay, den anderen Denkfehler schiebe ich mal nicht auf den Montag - die Verknüpfung über Min(id) = t.id klappt so nicht.
Also dann ein paar Zeichen länger:
Grüße
Biber
na okay, den anderen Denkfehler schiebe ich mal nicht auf den Montag - die Verknüpfung über Min(id) = t.id klappt so nicht.
Also dann ein paar Zeichen länger:
SELECT Top10Times.time,
d.Name AS Fahrer,
t.Minutes AS Minutes,
t.Seconds AS Seconds,
t.Milliseconds AS Milliseconds
FROM (select t.driverid,
t.trackId,
min((t.Minutes*60) + (t.Seconds) + (t.Milliseconds/1000)) AS time
from trackerneu.tracking t
Where t.sessionId in (2,3)
group by t.TrackID, t.driverID
) top10times,
trackerneu.tracking t,
trackerneu.driver d
WHERE t.trackID=Top10Times.TrackId
AND ((t.Minutes*60) + (t.Seconds) + (t.Milliseconds/1000)) =Top10Times.time
AND t.TrackID =84
AND t.DriverID = d.ID
ORDER BY 1 ASC
LIMIT 0 , 10
Grüße
Biber
Moin jhe1960,
eigentlich kann es nur daran liegen, dass in der unteren WHERE-Clause noch ein
fehlt.
Oder aber:
Es sei denn, der Wolfgang.hat tatsächlich zwei Bestrunden mit exakt derselben Zeit hingelegt.
Wenn es das ist: Ergänze oben direkt nach dem Wort SELECT noch das Wort DISTINCT.
Grüße
Biber
eigentlich kann es nur daran liegen, dass in der unteren WHERE-Clause noch ein
AND t.sessionId in (2,3)
fehlt.
Oder aber:
Es sei denn, der Wolfgang.hat tatsächlich zwei Bestrunden mit exakt derselben Zeit hingelegt.
Wenn es das ist: Ergänze oben direkt nach dem Wort SELECT noch das Wort DISTINCT.
Grüße
Biber
Moin jhe1960,
wenn in der tracknum.php stehen würde
...dann müsste dein Statement in dieser Form klappen
Oder eventuell sicherheitshalber gecastet mit
Grüße
Biber
wenn in der tracknum.php stehen würde
$createdat = '2012-02-02 00:00:00';
...dann müsste dein Statement in dieser Form klappen
...
$sql = "SELECT driver.Name AS Fahrer, COUNT(tracking.Lap) AS lAps FROM tracking, driver where tracking.TrackID = 82 AND tracking.DriverID = driver.ID AND tracking.VehicleID = 124 AND CreatedAt < $createdat GROUP BY Fahrer ORDER BY lAps DESC LIMIT 0,5";
Oder eventuell sicherheitshalber gecastet mit
...and CreatedAt < cast($createdat as DateTime)...
Grüße
Biber
Moin jhe1060,
ich mag Montage ja auch...
versuche es mal so:
Wenn das nicht hilft, dann müssen wir auf eine/n mySQL-Kundige/n warten... oder auf einen Dienstag...
[Edit] Etwas lesbarer wäre es so:
[/Edit]
Grüße
Biber
ich mag Montage ja auch...
versuche es mal so:
$sql = "SELECT driver.Name AS Fahrer, COUNT(tracking.Lap) AS lAps FROM tracking, driver where tracking.TrackID = 82 AND tracking.DriverID = driver.ID AND tracking.VehicleID = 124 AND CreatedAt < '".$createdat."' GROUP BY Fahrer ORDER BY lAps DESC LIMIT 0,5";
Wenn das nicht hilft, dann müssen wir auf eine/n mySQL-Kundige/n warten... oder auf einen Dienstag...
[Edit] Etwas lesbarer wäre es so:
$sql = "SELECT driver.Name AS Fahrer, COUNT(tracking.Lap) AS lAps";
$sql .= " FROM tracking, driver";
$sql .= " WHERE tracking.TrackID = 82";
$sql .= " AND tracking.DriverID = driver.ID";
$sql .= " AND tracking.VehicleID = 124";
$sql .= " AND CreatedAt < '".$createdat."' ";
$sql .= " GROUP BY Fahrer ORDER BY lAps DESC LIMIT 0,5";
Grüße
Biber
Moin jhe1960,
das Hinterlegen eines "<" oder ">"-Zeichens in einer Variablen/in einer include-Datei würde ich nicht als Option wählen, selbst wenn es rein handwerklich ginge. Das mindert die Lesbarkeit des Statements und - viel wichtiger- nimmt dem Optimizer jegliche Möglichkeit, irgendwelche Zugriffspfade zu bestimmen.
Wenn du denn flexiblen Zugriff auf "Datum Kleiner als"/"Datum größer als"/"Datum gleich" über diese Include-Datei brauchst, dann definiere dort zwei Variablen:
und ändere dein
So kannst du alle Fälle abbilden.
Ich habe hier bewusst die zwei Bedingungen "<=" und ">=" genommen statt
, da mySQL meiner Erinnerung nach den Max-Wert/die Obergrenze ausschliesst.
Du würdest also, wenn mincreatedat und maxcreatedat gleich sind, oder allgemein wenn Obergrenze und Untergrenze gleich sind, mit BETWEEN niemals ein Ergebnis erhalten.
Grüße
Biber
das Hinterlegen eines "<" oder ">"-Zeichens in einer Variablen/in einer include-Datei würde ich nicht als Option wählen, selbst wenn es rein handwerklich ginge. Das mindert die Lesbarkeit des Statements und - viel wichtiger- nimmt dem Optimizer jegliche Möglichkeit, irgendwelche Zugriffspfade zu bestimmen.
Wenn du denn flexiblen Zugriff auf "Datum Kleiner als"/"Datum größer als"/"Datum gleich" über diese Include-Datei brauchst, dann definiere dort zwei Variablen:
$mincreatedat = '2013-02-02 00:00:00';
$maxcreatedat = '2013-03-31 00:00:00';
und ändere dein
$sql
inSELECT driver.Name AS Fahrer, COUNT( tracking.Lap ) AS lAps
FROM tracking, driver
WHERE tracking.TrackID in ($track)
AND tracking.DriverID = driver.ID
AND tracking.VehicleID in ($car)
AND CreatedAt >= ('".$mincreatedat."')
AND CreatedAt <= ('".$maxcreatedat."')
GROUP BY Fahrer
ORDER BY lAps DESC
LIMIT 0 , 5
So kannst du alle Fälle abbilden.
Ich habe hier bewusst die zwei Bedingungen "<=" und ">=" genommen statt
.."AND CreatedAt BETWEEN ('".$mincreatedat."') and ('".$maxcreatedat."')
, da mySQL meiner Erinnerung nach den Max-Wert/die Obergrenze ausschliesst.
Du würdest also, wenn mincreatedat und maxcreatedat gleich sind, oder allgemein wenn Obergrenze und Untergrenze gleich sind, mit BETWEEN niemals ein Ergebnis erhalten.
Grüße
Biber
Moin jhe1960,
naja, verwunderlich ist aber das ausgegebene Ergebnis nicht wirklich,
In der "group by"-Clause des "Top10Times"-Subselect steht schwarz auf weiss (oder zumindest dunkel auf hellem Grund)
... also gruppieren/ermittle die Bestzeiten je Kombination Track/Fahrer/Fahrzeug.
und das macht die Query - - works as designed.
Für die jetzt gewünschte Abfrage musst du das letzte Gruppierfeld "t.VehicleID" aus der Group-By-Klausel entfernen und die t.VehicleID auch aus der Feldliste der "Top10Times" rausnehmen.
So in etwa sollte es werden:
Grüße
Biber
.
naja, verwunderlich ist aber das ausgegebene Ergebnis nicht wirklich,
In der "group by"-Clause des "Top10Times"-Subselect steht schwarz auf weiss (oder zumindest dunkel auf hellem Grund)
... group by t.TrackID, t.driverID, t.VehicleID ..
... also gruppieren/ermittle die Bestzeiten je Kombination Track/Fahrer/Fahrzeug.
und das macht die Query - - works as designed.
Für die jetzt gewünschte Abfrage musst du das letzte Gruppierfeld "t.VehicleID" aus der Group-By-Klausel entfernen und die t.VehicleID auch aus der Feldliste der "Top10Times" rausnehmen.
So in etwa sollte es werden:
$sql = "SELECT DISTINCT Top10Times.time,
d.Name AS Fahrer,
t.Minutes AS Minutes,
t.Seconds AS Seconds,
t.Milliseconds AS Milliseconds
FROM (select t.driverid,
t.trackId, -- raus: t.VehicleID,
min((t.Minutes*60) + (t.Seconds) + (t.Milliseconds/1000)) AS time
from trackerneu.tracking t
Where t.sessionId in ($session)
AND t.VehicleID in ($car) -- diese Bedingung nach oben
group by t.TrackID, t.driverID -- Raus: , t.VehicleID
) top10times,
trackerneu.tracking t,
trackerneu.driver d
WHERE t.trackID=Top10Times.TrackId
AND ((t.Minutes*60) + (t.Seconds) + (t.Milliseconds/1000)) =Top10Times.time
AND t.TrackID = $track
AND t.DriverID = d.ID
AND t.sessionId in ($session)
-- Bedingung ging nach oben..
AND CreatedAt >= ('".$mincreatedat."')
AND CreatedAt <= ('".$maxcreatedat."')
ORDER BY 1 ASC
LIMIT 0 , 5";
Grüße
Biber
.
Moin Jürgen,
uups, da fehlt wohl noch ein Feld in dem Join zwischen Top10Times und tracking.
Bitte ergänze nach Zeile 16 noch ein
Und (was jetzt nichts mit diesem Problem zu tun hat) nimm auch die gestern "nach oben verschobene Bedingung"
noch mal redundant wieder mit rein eine Zeile tiefer.
Denn auch da könnte es zu falschen Verjoinungen kommen bei konstruierbaren Datenkonstellationen.
Grüße
Biber.
uups, da fehlt wohl noch ein Feld in dem Join zwischen Top10Times und tracking.
Bitte ergänze nach Zeile 16 noch ein
AND Top10Times.driverID = t.DriverID
Und (was jetzt nichts mit diesem Problem zu tun hat) nimm auch die gestern "nach oben verschobene Bedingung"
AND t.VehicleID in ($car)
noch mal redundant wieder mit rein eine Zeile tiefer.
Denn auch da könnte es zu falschen Verjoinungen kommen bei konstruierbaren Datenkonstellationen.
Grüße
Biber.
Moin Jürgen,
da hast du dir aber ein schön entspannendes Hobby zugelegt... sicherlich das Richtige zum Abchillen bei dieser Hitze.
Also: natürlich als erster Tipp: gewöhn dem "der-in-die-Datentabelle-schreibt"-Prozess das ab, je nach Laune oder Wochentag mal drei, mal vier Ziffern in die Tabelle zu schreiben.
Wenn wir es aber momentan als gegeben/nicht abstellbar hinnehmen müssen, dann müssen wir wohl (oder übel) eine Fallunterscheidung machen. Auf SQL heisst dat dann SELECT CASE WHEN expr THEN bla ELSE blubb END.
Wenn ich das Problem richtig verstanden habe, dann stehen im Feld "milliseconds" zB die Werte
11 --> der Wert meint 11 Millisekunden == 0,011 sec
365 --> der Wert meint 365 Millisekunden == 0,365 sec
2345 --> dieser Wert meint 234,5 Millisekunden == 0,2345 sec.
Mit meinen geringen Mathekenntnissen bzw Erinnerungsbruchstücken aus der Schulzeit würden mir zwei Stategien einfallen, um jeweils auf ein "genormtes" Ergebnis zu kommen:
a) Wenn Input-Wert < 1000 dann dividiere durch 1000 andernfalls dividiere durch 10000
b) [mit brutaler impliziter Typkonvertierung.] Dividiere Inputwert durch 10 hoch Maximum(Länge(Inputwert), 3)
die zweite Variante ist eher was für EXCELaner.
Wenn du da in einer Tabelle in Zellen A1/A2/A3 die Werte 11/365/2345 stehen hättest, dann wäre die Formel in Zelle B1 ungefähr
=A1/10^MAX(LÄNGE(A1);3)
Würde funktionieren - aber brutalstmögliche implizite Typkonvertierung lassen wir mal für Excel-Anwendungen und somit in SQL-Statements draussen.
Variante a) würde also bedeuten, wir interpretieren die t.milliseconds unterschiedlich, je nachdem ob dort ein Wert < 1000 oder >= 1000 abgelegt ist.
Nur als proof-of-concept:
Wenn mit dieser (ungetesteten) Probe-Abfrage brauchbare Werte für die beiden errechneten Felder "Normmsec" (soll sinngemäß Norm-Millisekunden bedeuten) und NKmsec (lies: Nachkomma-Sekunden) angezeigt werden, dann können wir überall dort, wo jetzt ein "t.milliseconds" in der Abfrage steht, eine der CASE-Varianten einbauen.
Aber prüfe bitte erst, ob ich das Problem richtig verstanden habe und was so eine TestAbfrage liefert.
Grüße
Biber
da hast du dir aber ein schön entspannendes Hobby zugelegt... sicherlich das Richtige zum Abchillen bei dieser Hitze.
Also: natürlich als erster Tipp: gewöhn dem "der-in-die-Datentabelle-schreibt"-Prozess das ab, je nach Laune oder Wochentag mal drei, mal vier Ziffern in die Tabelle zu schreiben.
Wenn wir es aber momentan als gegeben/nicht abstellbar hinnehmen müssen, dann müssen wir wohl (oder übel) eine Fallunterscheidung machen. Auf SQL heisst dat dann SELECT CASE WHEN expr THEN bla ELSE blubb END.
Wenn ich das Problem richtig verstanden habe, dann stehen im Feld "milliseconds" zB die Werte
11 --> der Wert meint 11 Millisekunden == 0,011 sec
365 --> der Wert meint 365 Millisekunden == 0,365 sec
2345 --> dieser Wert meint 234,5 Millisekunden == 0,2345 sec.
Mit meinen geringen Mathekenntnissen bzw Erinnerungsbruchstücken aus der Schulzeit würden mir zwei Stategien einfallen, um jeweils auf ein "genormtes" Ergebnis zu kommen:
a) Wenn Input-Wert < 1000 dann dividiere durch 1000 andernfalls dividiere durch 10000
b) [mit brutaler impliziter Typkonvertierung.] Dividiere Inputwert durch 10 hoch Maximum(Länge(Inputwert), 3)
die zweite Variante ist eher was für EXCELaner.
Wenn du da in einer Tabelle in Zellen A1/A2/A3 die Werte 11/365/2345 stehen hättest, dann wäre die Formel in Zelle B1 ungefähr
=A1/10^MAX(LÄNGE(A1);3)
Würde funktionieren - aber brutalstmögliche implizite Typkonvertierung lassen wir mal für Excel-Anwendungen und somit in SQL-Statements draussen.
Variante a) würde also bedeuten, wir interpretieren die t.milliseconds unterschiedlich, je nachdem ob dort ein Wert < 1000 oder >= 1000 abgelegt ist.
Nur als proof-of-concept:
SELECT t.Milliseconds AS originalMilliseconds
, CASE when t.milliseconds < 1000 then t.milliseconds else t.milliseconds/10 end as Normmsec
, CASE when t.milliseconds < 1000 then t.milliseconds/1000 else t.milliseconds/10000 end as NKsec
FROM trackerrf2.tracking t
LIMIT 0,50
Wenn mit dieser (ungetesteten) Probe-Abfrage brauchbare Werte für die beiden errechneten Felder "Normmsec" (soll sinngemäß Norm-Millisekunden bedeuten) und NKmsec (lies: Nachkomma-Sekunden) angezeigt werden, dann können wir überall dort, wo jetzt ein "t.milliseconds" in der Abfrage steht, eine der CASE-Varianten einbauen.
Aber prüfe bitte erst, ob ich das Problem richtig verstanden habe und was so eine TestAbfrage liefert.
Grüße
Biber
Moin Jürgen,
na ja, der Rest ist eigentlich nur noch das Ersetzen der t.Milliseconds-Werte durch die Fallunterunterscheidung.
Um die Millisekunden einheitlich auf 3 Stellen zu trimmen, gäbe es die Funktionen FLOOR() bzw ROUND().
Sprich: wenn der Originalwert die Zahl 3517 wäre, was dann 351,7 msec wären, dann würde FLOOR(3157/10) es "abschneiden" auf die Ganzzahl 351.
Die Funktion ROUND() dagegen würde es in diesem Fall aufrunden als ROUND(3517/10) auf die Ganzzahl 352.
Ich würde ja eher "runden" statt die letzte Stelle abzuschneiden, aber das kannst du machen wiedewutt.
Dein Statement sähe (ungefähr) so aus nach dem Ersetzen von t.milliseconds durch CASE WHEN..END
Kann sein, dass ich jetzt eine Klammer-Auf zuviel oder eine Klammer-Zu zuwenig habe - ich habe es eben nur im Editor versucht.
Das Prinzip sollte aber erkennbar sein.
Und: ja - das Statement ist dadurch um 20% länger geworden.
Aber: nein - die Laufzeit geht nicht im selben Verhältnis nach oben.
Grüße
Biber
na ja, der Rest ist eigentlich nur noch das Ersetzen der t.Milliseconds-Werte durch die Fallunterunterscheidung.
Um die Millisekunden einheitlich auf 3 Stellen zu trimmen, gäbe es die Funktionen FLOOR() bzw ROUND().
Sprich: wenn der Originalwert die Zahl 3517 wäre, was dann 351,7 msec wären, dann würde FLOOR(3157/10) es "abschneiden" auf die Ganzzahl 351.
Die Funktion ROUND() dagegen würde es in diesem Fall aufrunden als ROUND(3517/10) auf die Ganzzahl 352.
Ich würde ja eher "runden" statt die letzte Stelle abzuschneiden, aber das kannst du machen wiedewutt.
Dein Statement sähe (ungefähr) so aus nach dem Ersetzen von t.milliseconds durch CASE WHEN..END
SELECT DISTINCT Top10Times.time,
d.Name AS Fahrer,
t.Minutes AS Minutes,
t.Seconds AS Seconds,
case when t.Milliseconds < 1000 then t.Milliseconds
else Round(t.Milliseconds/10) end AS Milliseconds
FROM (select t.driverid,
t.trackId,
min((t.Minutes*60) + (t.Seconds) + (
case when t.Milliseconds<1000 then t.milliseconds/1000
else Round(t.milliseconds/10000) end )) AS time
from trackerrf2.tracking t
Where t.sessionId in ($session)
AND t.VehicleID in ($car)
group by t.TrackID, t.DriverID
) top10times,
trackerrf2.tracking t,
trackerrf2.driver d
WHERE t.trackID=Top10Times.TrackId AND Top10Times.driverID = t.DriverID
AND t.VehicleID in ($car)
AND ((t.Minutes*60) + (t.Seconds) + (
case when t.Milliseconds<1000 then t.milliseconds/1000
else Round(t.milliseconds/10000) end)) =Top10Times.time
AND t.TrackID = $track
AND t.DriverID = d.ID
AND t.sessionId in ($session)
AND CreatedAt >= ('".$mincreatedat."')
AND CreatedAt <= ('".$maxcreatedat."')
ORDER BY 1 ASC
LIMIT 0,5
Kann sein, dass ich jetzt eine Klammer-Auf zuviel oder eine Klammer-Zu zuwenig habe - ich habe es eben nur im Editor versucht.
Das Prinzip sollte aber erkennbar sein.
Und: ja - das Statement ist dadurch um 20% länger geworden.
Aber: nein - die Laufzeit geht nicht im selben Verhältnis nach oben.
Grüße
Biber
Moin Jürgen,
sorry, heute schiebe ich es mal auf die sommerliche Hitze....("Montag" fällt ja leider als Ausrede aus).
Ich habe gestern zuviel gecopy&pasted, denn die ROUND()-Funktion ist nur nötig bei der "Berechnung" des Feldes "Milliseconds" im Resultset,
In den Berechungen der Zeit ist ein Runden der Nachkommastellen auf den nächstliegenden Integerwert ... ääähm... nicht zielführend.
Siehst du ja in deinem unteren 3-Zeilen-Resultset.
Bei allen drei Fahrern werden aus 2 min+1 sec -> 121sec (ok) und aus den zur Ganzzahl geROUNDeten 0,187sec (und den folgenden Werten) logischerweise glatte 0sec.
Daher kommen die auch bei einem "ORDER BY 1 ASC", also nach der ersten Spalte sortiert in irgendeiner zufälligen Reihenfolge - die sind ja "gleichwertig"
Also - ich will nicht nochmal das Statement komplett zitieren - nimm in der Zeile 11 und 23 des Statements die Funktion ROUND() bitte raus, also in diesen Zeilen vom "else" bis zum "end" nur noch
Grüße
Biber
sorry, heute schiebe ich es mal auf die sommerliche Hitze....("Montag" fällt ja leider als Ausrede aus).
Ich habe gestern zuviel gecopy&pasted, denn die ROUND()-Funktion ist nur nötig bei der "Berechnung" des Feldes "Milliseconds" im Resultset,
In den Berechungen der Zeit ist ein Runden der Nachkommastellen auf den nächstliegenden Integerwert ... ääähm... nicht zielführend.
Siehst du ja in deinem unteren 3-Zeilen-Resultset.
Bei allen drei Fahrern werden aus 2 min+1 sec -> 121sec (ok) und aus den zur Ganzzahl geROUNDeten 0,187sec (und den folgenden Werten) logischerweise glatte 0sec.
Daher kommen die auch bei einem "ORDER BY 1 ASC", also nach der ersten Spalte sortiert in irgendeiner zufälligen Reihenfolge - die sind ja "gleichwertig"
Also - ich will nicht nochmal das Statement komplett zitieren - nimm in der Zeile 11 und 23 des Statements die Funktion ROUND() bitte raus, also in diesen Zeilen vom "else" bis zum "end" nur noch
else t.milliseconds/10000 end
stehen lassen.Grüße
Biber
Moin Jürgen,
ich hätte nur zwei Erklärungen für dieses Migrationsproblem.
a) entweder ist eine der Parametervariablen (noch) nicht richtig gesetzt worden nach der Umstellung
b) bei der "neuen" DB-Instanz macht der leichtsinnigerweise gewählte Feldname "time" Probleme, weil das ein reserviertes Wort in SQL ist.
Bitte prüfen, ob die Abfrage mit dem Feldnamen "zeit" statt "time" läuft und ob alle Parameter richtig sind.
Grüße
Biber
ich hätte nur zwei Erklärungen für dieses Migrationsproblem.
a) entweder ist eine der Parametervariablen (noch) nicht richtig gesetzt worden nach der Umstellung
b) bei der "neuen" DB-Instanz macht der leichtsinnigerweise gewählte Feldname "time" Probleme, weil das ein reserviertes Wort in SQL ist.
Bitte prüfen, ob die Abfrage mit dem Feldnamen "zeit" statt "time" läuft und ob alle Parameter richtig sind.
Grüße
Biber