Fehler in MySQL Abfrage
Christian
- php
Hallo,
ich habe folgende Datenbankabfrage:
$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);
$week = week($firstweek, $firstyear);
$weekstart = $week[0];
$weekend = $week[1];}
$now = time();
echo $now."<br />";
while ($weekstart <= $now) {
$query = "SELECT * FROM training WHERE date >= '".$weekstart."' AND date <= '".$weekend."' ORDER BY date";
$result = mysql_query($query);
while($row = mysql_fetch_object($result))
{$date = $row->date;
$calweek = date("W",$date[0]);
$year = date("Y",$date[0]);
echo $calweek."<br />";
echo $year."<br />";
$numberofresults = mysql_num_rows($result);
echo $weekstart."<br />";
echo $numberofresults."<br />";
$calweek++;
$week = week($calweek, $year);
$weekstart = $week[0];
$weekend = $week[1];
echo $weekstart."<br />";}
}
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
Das heißt die erste Ausgabe es die des aktuellen Timestamps, die zweite Ausgabe ist die ausgelesene Woche und die dritte das ausgelesene Jahr, und dort liegt offensichtlich der Fehler. Der erste Wochenbeginn (4. Ausgabe) ist zwar noch richtig, dafür findet die Abfrage auch noch die Anzahl der Einträge (5. Ausgabe), Dann kanns ja aber nicht mehr gehen, da das Programm mit einer Woche beginnt, die Jahrzente zurückliegt und für die es ja auch keine Einträge gibt.
Woran kann es liegen, dass das Skript aus dem ausgelesenen Datum nicht die richtige Woche bzw. Jahr auslesen kann?
Danke im Voraus,
Christian
Hallo nochmal,
ich habe mir jetzt $date[0] ausgeben lassen und kriege 1. Der nächste Eintrag unter date in der Datenbank ist aber 1187820000.
Wo kann da der Fehler liegen?
Danke,
Christian
Hallo Christian,
ich habe mir jetzt $date[0] ausgeben lassen und kriege 1. Der nächste Eintrag unter date in der Datenbank ist aber 1187820000.
erstens ist der "nächste" Datensatz in der Tabelle völlig uninteressant. Du
fragst den kleinsten Wert in der Spalte "date" der Tabelle "training" ab. Da
uns Deine gesamten Daten nicht vorliegen, können wir nicht wissen, was der kleinste Wert ist.
Wo kann da der Fehler liegen?
zweitens könnte der Fehler möglicherweise in Deiner Funktion
week(foo, bar)
liegen, deren Code - und deren Übergabewerte - Du uns freundlicherweise vorenthältst.
Meine Suche auf php.net war jedenfalls erfolglos.
Wie ich Dir bereits schrieb, ist Dein PHP-Code nicht nur falsch, sondern vermutlich auch überflüssig.
Freundliche Grüße
Vinzenz
Hallo Christian,
warum machst Du uns, Deinem Server und Dir selbst das Leben so schwer?
> $query = "SELECT date FROM training ORDER BY date LIMIT 1";
[...] Es folgt eine Menge unkommentierten PHP-Codes ...
... mit dem Einsatz einer undokumentierten Funktion:
> $week = week($firstweek, $firstyear);
...
> while ($weekstart <= $now) {
... und dem Absetzen von Abfragen an die Datenbank in einer Schleife, ...
> $query = "SELECT * FROM training WHERE date >= '".$weekstart."' AND date <= '".$weekend."' ORDER BY date";
... bei der viele, viele Daten abgefragt werden, "SELECT * " ist ja so bequem ...
> $result = mysql_query($query);
... mögliche Fehler munter ignoriert werden,
> while($row = mysql_fetch_object($result))
> {$date = $row->date;
... offensichtlich ein einziges Feld interessiert ...
> $numberofresults = mysql_num_rows($result);
... und die Anzahl der Datensätze, während der Rest weggeworfen wird ...
> }
und da Du irgendwo noch einen Fehler eingebaut hast, darfst Du Dich nicht wundern, dass Dein Skript viel zu lange braucht und zwangsweise beendet wird.
Ich vermute, Du möchtest in Erfahrung bringen, wieviele Einträge je Kalenderwoche und Jahr es in der Tabelle in einem bestimmten Zeitraum gibt. Wenn ja, so kannst Du dies mit einer relativ einfachen SQL-Abfrage bekommen, ohne irgendwelche überflüssigen PHP-Verrenkungen zu machen:
Da Du Deine Zeitangaben als UNIX-Timestamp abgespeichert hast, für den meiner
Meinung nach nichts spricht, als dass er in diversen Programmiersprachen
bequem zu bekommen ist, ist noch etwas zusätzlicher Aufwand erforderlich.
Grundsätzlich bin ich der Ansicht, dass man Datums- und Zeitangaben in
Datenbanken in Feldern entsprechenden Typs abspeichern sollte.
Zurück zu Deinem Problem:
Ein einziges Mal ausgeführt, sollte Dir
[code lang=sql]SELECT
-- 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
-- in einem bestimmten, von Dir vorgegebenen Zeitraum (hier als UNIX-Timestamps
WHERE date [link:http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#function_between@title=BETWEEN] dein_start AND dein_ende
-- gruppiert nach Kalenderwoche und Jahr, d.h. für jede Kombination von
-- Kalenderwoche und Jahr genau eine Zeile
GROUP BY Woche, Jahr
Dein Ergebnis liefern. Möchtest Du das Ergebnis über die kompletten Daten Deiner Tabelle sehen, so lass die WHERE-Klausel einfach weg.
Freundliche Grüße
Vinzenz
Hello,
warum machst Du Deinem Server das Leben so schwer?
... und dem Absetzen von Abfragen an die Datenbank in einer Schleife, ...
ohne das Resultset zwischendurch wieder freizugeben.
Das führt i.d.R. zu lost handles, wenn PHP nicht inzwischen eine eigene Lösung eingebaut hat.
Da bin ich im Moment überfragt, ob bei (unsachgemäßer) Wiederbelegung eines Handles der damit verknüpfte Speicherbereich wieder freigegeben wird.
Harzliche Grüße vom Berg
http://www.annerschbarrich.de
Tom
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
342000Fatal 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