Vinzenz Mai: PHP-Fehleranalyse und SQL-Lösungsvorschlag

Beitrag lesen

Hallo Christian,

es hat mir keine Ruhe gelassen ...

ich habe folgende Datenbankabfrage:

... die richtige Lösung für Dein Problem habe ich Dir bereits gegeben, sie
sollte wie folgt lauten:

SELCT  
    -- ermittle die Kalenderwoche  
    [link:http://dev.mysql.com/doc/refman/5.0/en/date-and-time-functions.html#function_week@title=WEEK]([link:http://dev.mysql.com/doc/refman/5.0/en/date-and-time-functions.html#function_from-unixtime@title=FROM_UNIXTIME](date)) AS Woche,  
    -- ermittle den Jahresanteil  
    [link:http://dev.mysql.com/doc/refman/5.0/en/date-and-time-functions.html#function_year@title=YEAR](FROM_UNIXTIME(date)) AS Jahr,  
    -- zähle wieviele Einträge es davon gibt  
    [link:http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_count@title=COUNT](date) AS Anzahl  
FROM training  
-- gruppiert nach Kalenderwoche und Jahr, d.h. für jede Kombination von  
-- Kalenderwoche und Jahr genau eine Zeile  
GROUP BY Woche, Jahr  
ORDER BY Jahr, Woche

Warum Dein Code in eine Endlosschleife läuft, ist mir inzwischen auch klar:

  

> $query = "SELECT date FROM training ORDER BY date LIMIT 1";  
> $result = mysql_query($query);  
>   
> while($row = mysql_fetch_object($result))  
>     {$date = $row->date;  
>     $firstweek = date("W",$date);  
>     $firstyear = date("Y",$date);  
  
# Deine Funktion week scheint richtig den Timestamp des  
# Wochenanfangs und des Wochenendes einer gegebenen Kalenderwoche  
# in einem gegebenen Jahr zu berechnen  
  

>     $week = week($firstweek, $firstyear);  
>     $weekstart = $week[0];  
>     $weekend = $week[1];}  
>   
> $now = time();  
> echo $now."<br />";  
  
# Ausgabe:  

> 1189713333  
  
  

> while ($weekstart <= $now) {  
  
# Solange der Inhalt von $weekstart nicht größer ist als der aktuelle Timestamp  
# 1. Durchlauf  
# $weekstart = 1186959600  
# $now       = 1189713333  
# Die äußere Schleife wird abgearbeitet  
  
# 2. Durchlauf  
# $weekstart = 342000  
# $now       = 1189713333  
# Die äußere Schleife wird abgearbeitet :-)  
  
# 3. Durchlauf und folgende Durchläufe  
# Da die innere Schleife übersprungen wurde,  
# da die Query keine Ergebnisse lieferte, bist Du in eine Endlosschleife  
# geraten. In diese kommst Du bei Deinem Skript immer, wenn die Query in  
# der Schleife _kein_ Ergebnis liefert. Du hast hier also einen logischen  
# Fehler eingebaut. Denn das gilt für _jede_ Woche, in der es keinen  
# Eintrag gibt, z.B. eine Trainingspause, Urlaub oder was weiß ich sonst ...  
  
  
# $weekstart = 342000  
# $now       = 1189713333  
# Die äußere Schleife wird abgearbeitet :-)  
  
  

>   
>   $query = "SELECT * FROM training WHERE date >= '".$weekstart."' AND date <= '".$weekend."' ORDER BY date";  
>   $result = mysql_query($query);  
  
# 1. Durchlauf: Es gibt genau 1 Ergebnis, siehe Deine fünfte Ausgabe:  

> 1  
  
# 2. Durchlauf der äußeren Schleife  
# Es gibt kein Ergebnis, denn Du hast keine Werte aus KW2 von 1970  
  

>   while($row = mysql_fetch_object($result))  
  
# 1. Durchlauf der äußeren Schleife:  
# Es gibt ein Ergebnis, die innere Schleife wird abgearbeitet.  
  
# 2. Durchlauf der äußeren Schleife  
# Es gibt keine Ergebnisse, die innere Schleife wird nicht abgearbeitet  
  

>     {$date = $row->date;  
  
# Laut Deinem zweiten Posting bekommst Du folgenden Wert:  
# 1187820000  
  
# Und nun kommt einer von mehreren Fehlern:  
  

>     $calweek = date("W",$date[0]);  
  
# Du greifst auf $date, das eine Integer enthält, wie auf ein Array zu.  
# PHP konvertiert daher $date in eine Zeichenkette und Du greifst über  
# $date[0] auf das erste Zeichen dieser Zeichenkette zurück, hat also  
# den Wert 1  
  
# 1. Durchlauf:  
#     $calweek = date("W", 1);  
#     $year    = date("Y", 1);  
  
# Da der UNIX-Timestamp ab dem 1. Januar 1970 läuft,  
  

>     $year = date("Y",$date[0]);  
  
# ergeben sich logischerweise die Ausgaben  
  

>     echo $calweek."<br />";  
  
#     01  
  

>     echo $year."<br />";  
  
#     1970  
  

>     $numberofresults = mysql_num_rows($result);  
>     echo $weekstart."<br />";  
  
#     1186959600  
  

>     echo $numberofresults."<br />";  
  
#     1  
  
# Anmerkung:  
# Bei mehreren Einträgen in einem Intervall bekämst Du auch entsprechend  
# viele Zeilen zu dieser Woche, das ist bestimmt nicht gewünscht.  
  
  

>     $calweek++;  
  
#     $calweek enthält nun den Wert 2  
  

>     $week = week($calweek, $year);  
>     $weekstart = $week[0];  
  
#  $weekstart enthält nun den Timestamp des Beginns der zweiten KW 1970 :-)  
  

>     $weekend = $week[1];  
  
#  $weekend den Timestamp des Endes der zweiten KW 1970.  
# und es ist ein ganz schlimmer Fehler, diese Änderung hier an dieser Stelle  
# zu machen. Du landest nämlich _immer_ in einer Endlosschleife, sobald es  
# in irgendeiner Woche keinen Eintrag gibt. Auch dann, wenn Du obigen Fehler  
# bereinigt hast.  
  

>     echo $weekstart."<br />";}  
  

> 342000  
  

>   
> }  
  
# 1. Durchlauf ist abgearbeitet, nun geht es an das Überprüfen der  
# Abbruchbedingung - siehe oben  
  
# 2. Durchlauf:  
# Die innere Schleife wurde nicht abgearbeitet  
# $weekstart hat immer noch den Wert 342000 ...  
# Es geht zum dritten Durchlauf ...  

Ein Testen dieser Abfrage ergibt folgende Ausgabe:

1189713333
01
1970
1186959600
1
342000

Fatal error: Maximum execution time of 30 seconds exceeded in /[...]/weekoutput.php on line 24

Wie von mir angemerkt, hilft Dir eine Beseitigung Deines fehlerhaften Zugriffs
$date statt $date[0] nicht weiter.

Bei mehr als einem Eintrag in der Woche bekommst Du unerwünschte
Mehrfachausgaben für die gleiche Woche, bei einer Woche ohne Einträge
landest Du wieder in der Endlosschleife.
Zudem verbraucht Dein Skript unnötige Ressourcen, selbst wenn ein Index auf
der Spalte "date" liegt.

Löse daher Deine Aufgabe mit SQL (siehe oben) statt mit PHP.

Freundliche Grüße

Vinzenz