Durchschnittsdauer berechnen

Bratkartoffel

gebratene Kartoffel
Premium-User
Hallo,

soll für einen Kunden ein kleines Programm schreiben, wo ich jetzt absolut nicht weiter weiß. In der Datenbank sind mehrere Einträge mit einer Startzeit und Endzeit eingetragen. Der Einfachheit halber hab ich das ganze (für PHP) in MySQL als Datentyp integer gespeichert, spricht als Unix Timestamp.

Nun hab ich mir gedacht, dass ich mit der Query ...

SQL:
SELECT
  MIN(Ende-Beginn) minimal,
  MAX(Ende-Beginn) maximal,
  AVG(Ende-Beginn) durchschnitt
FROM
......

und dem PHP Teil

PHP:
  ...
  $Durchschnitt=$ergebnis->durchschnitt;
  
  echo date("H:i", $Durchschnitt);

die Durchschnittsdauer ausgeben kann. Nun, leider falsch gedacht, sonst wäre der Post hier überflüssig ;)

Die minimale und maximale Dauer gibt er einwandfrei aus, aber bei der Durchschnittsdauer kommt ein Wert < der minimalen Dauer raus, was nicht stimmen kann.

Was hab ich falsch gemacht

Ach ja, bin mir nicht sicher, ob das jetzt im richtigen Unterforum steht, war mir nicht sicher ob ichs in PHP oder Relationale Datenbanken posten sollte ;)

Gruß
Bratkartoffel
 
Also ich würde das ein wenig anders löse:

Um den Durchschnitt zu errechnen brauchst du doch alle Zeiten.
Addier doch gleich alle differenzen zwischen ende und start zusammen. Nebenbei lässt du in ner Variable die Durchläufe mitzählen und teilst den Wert der Addition nachher durch die anzahl der Zeilen in der MySQL Tabelle.

PHP:
$durchschnitt_sql_query=mysql_query(..........................);
while($sql_durchschnitt=mysql_fetch_array($durchschnitt_sql_query))
{
$count=$count + 1;
$add= $add + ($sql_durchscnitt['ende'] - $sql_durchscnitt['start']);
}
$durchschnitt = $add/$count;

Ich habe den Code jetzt nicht getestet aber so in der Art sollte es funkionieren.


LG nino
 
Hi,

erst mal danke für deinen Post.

Ja, so was in der Art hab ich mir auch schon gedacht, jedoch hab ich vergessen, euch was wichtiges mitzuteilen.

Es geht in meinem Fall um ein online Fangbuch für einen Fischerverein.

Der trägt seinen Tag ein, Startzeit, Fangzeit, Endzeit.

So, damit hätte ich die Dauer einer Session von Endzeit-Startzeit, wenn ich das bei allen Einträgen der DB machen würde. ABER... Was ist, wenn der Angler mal 2 Fänge während einer Session gefangen hat? Dann wären es 2 Einträge in der Datenbank, wobei er aber die Dauer nur 1x nehmen soll. Dazu mach ich das "GROUP BY" im SQL Befehl.

Hier mal die beiden Funktionen, die ich zum ausrechnen der Gesamtdauer und der Anzahl der Sessions nehme.

PHP:
function Sessions() //Liefert die Anzahl der Sessions zurück (im unteren Beispiel 3, das stimmt so)
	{
		include("./include/db_config.inc.php");
		session_start();
		
		$link=mysql_connect($db->Server, $db->User, $db->Password);
		mysql_select_db($db->Database);
		
		$query="SELECT
							COUNT(*) zahl
						FROM
							faenge
						WHERE
							Faenger='" . $_SESSION['fangbuch_user'] . "'
						GROUP BY
							Beginn;";
		$result=mysql_query($query);
		$temp=0;
		
		while($Temp=mysql_fetch_object($result))
			$temp++;
		
		return $temp;
	}

function SessionsGesamtDauer() // Soll die Gesamtdauer der Sessions holen; Gibt aber nen falschen Wert zurück...
	{
		include("./include/db_config.inc.php");
		session_start();
		
		$link=mysql_connect($db->Server, $db->User, $db->Password);
		mysql_select_db($db->Database);
		
		$query="SELECT 
							SUM(Ende-Beginn) dauer
						FROM 
							faenge
						WHERE 
							Faenger='" . $_SESSION['fangbuch_user'] . "'
						GROUP BY 
							Beginn;";
		$result=mysql_query($query);
		$dauer=0;
		
		while($ergebnis=mysql_fetch_object($result))
			$dauer+=$ergebnis->dauer;
		
		return $dauer;
		
	}

Im Moment habe ich 4 Datensätze in der DB:

Code:
mysql> select ID, Beginn, Fangzeit, Ende from faenge where 1;
+----+------------+------------+------------+
| ID | Beginn     | Fangzeit   | Ende       |
+----+------------+------------+------------+
|  1 | 1202868000 | 1202871600 | 1202875200 | 
|  2 | 1202817600 | 1202821200 | 1202828400 | 
|  3 | 1202630400 | 1202644800 | 1202644800 | 
|  4 | 1202868000 | 1202873400 | 1202875200 | 
+----+------------+------------+------------+
4 rows in set (0.00 sec)

Hier die Dauer der Einträge mal in menschlich lesbarer Form:

Code:
  ID 1: 2 Std
  ID 2: 3 Std
  ID 3: 4 Std
  (ID 4: 2 Std)

Diese 4 Datensätze sagen mir es wurden zwar 4 Fänge eingetragen, aber es sind nur 3 Sessions (man beachte die selbe Beginn- / Endzeit bei ID 1 und 4).

Code:
mysql> select count(*) from faenge where 1 group by Beginn;
+----------+
| count(*) |
+----------+
|        1 | 
|        1 | 
|        2 | 
+----------+
3 rows in set (0.00 sec)

3 rows = 3 Sessions, klar, passt so.

Wenn ich nun die Funktion SessionsGesamtDauer manuell per mysql Konsole ausführe kommt folgendes:

Code:
mysql> select ID, sum(Ende-Beginn) dauer from faenge where 1 group by Beginn;
+----+-------+
| ID | dauer |
+----+-------+
|  3 | 14400 | 
|  2 | 10800 | 
|  1 | 14400 | 
+----+-------+
3 rows in set (0.00 sec)

Er gibt mir die Dauer der Einträge 1-3 aus, aber die ist falsch!


Er sollte doch eigentlich folgendes zurückgeben:
Code:
mysql> select sum(Ende-Beginn) dauer from faenge where 1 group by Beginn;
+-------+
|dauer |
+-------+
| 7200 | 
| 10800 | 
| 14400 | 
+----+-------+
3 rows in set (0.00 sec)


Warum gibt er mir das 7200 nicht aus, und das 14400 2x?

Wenn ich jetzt die 11 Stunden durch 3 teile, kommen gut 3,5 Std raus, es sollten aber genau 3 Stunden sein...

Tut mir Leid für meinen ersten Post, der war ziemlich undeutlich formuliert.

Hoffe, ihr versteht jetzt, wo der Hund begraben liegt, und könnt mir helfen...
 
Zuletzt bearbeitet:
Hi,

Er sollte nun eigentlich als Gesamtdauer der Sessions 9 Stunden zurückgeben,[...]

Nö. ;)
Was Du mit der Gruppierung erreichst, ist, dass Du für jede Gruppe eine Aufsummierung bekommst. ID 1 und 4 bilden in dem Fall eine Gruppe und die Summe für diese Gruppe sind halt 4 Stunden.

Villeicht hilft Dir DISTINCT weiter. Besser wäre allerdings, das DB-Design zu ändern.

LG
 
// EDIT

Ich habs... Wie der Vorgänger schon gesagt hat, wird die Gruppe zusammengezählt. Deshalb mach ichs jetzt so:

Code:
mysql> select Ende, Beginn from faenge where 1 group by Beginn;
+------------+------------+
| Ende       | Beginn     |
+------------+------------+
| 1202644800 | 1202630400 | 
| 1202828400 | 1202817600 | 
| 1202875200 | 1202868000 | 
+------------+------------+
3 rows in set (0.00 sec)

Die Dauer rechne ich jetzt in PHP aus :)

Danke, danke, danke!! :D
 
Zuletzt bearbeitet:
Es hört sich nun vielleicht ein wenig hart an, aber lieber du änderst die DB als das du mit einem schlechten Design weiter machst.

Am besten du überlegst dir nochmal das Design, den sonst bekommst du wahrscheinlich noch viel mehr Probleme, sollte es nicht sauber sein. Denn ein schlechtes Design durch Programmieren und SQL-Befehle zu verbessern ist sehr schwierig und funktioniert nicht immer.
 
Was meinst du eigentlich genau mit schlechtem Design?

Gut, ich hab als Datentyp in der DB nicht date sondern int, aber das sit schon das einzige, was nicht passt (hoff ich mal) ;)
 
Z.B. könntest du gleich das Datum speichern wann der Fang gemacht wurde und wenn es mehrere Fänge zur selben Zeit gibt, diese in einer Spalte angeben. Anstatt mehre Datensätze zu haben.
 
Aber ist das nicht eigentlich Ansichtssache, wie man das macht? Ob alles in einem Eintrag, und dann von dort mit PHP "explode" trennen, oder mehrere Datensätze, für jeden einen Fang?
 
Hi,

ich würde eher die "Fang-Sessions" in eine Tabelle speichern und die Fänge über die ID der jeweiligen Session zuordnen. Dein Problem ist doch die Datenredundanz bei der Start- und Endzeit, das man üblicherweise durch Normalisierung löst.

LG
 

Neue Beiträge

Zurück