scheitere an der benutzung von 'mysql_num_rows'
Paco
- php
0 Sven Rautenberg0 Paco0 Bademeister0 dedlfix
0 dedlfix
0 Bademeister0 dedlfix
0 Bademeister0 dedlfix
Hallo!
Es tut mir leid, daß ich mich mit solch einem Idiotenproblem an euch wende, aber komm gerade einfach wirklich nicht weiter.
sehr einfache Aufgabe:
Ich möchte einen datenbank-INSERT davon abhängig machen, ob ein solcher Eintrag bereits vorhanden ist.
Dazu mache ich eine simple SELECT-abfrage nach dem entsprechenden Feld und möchte mit mysql_num_rows abfragen wieviele Ergebnisse diese lieferte.
/*verbindet zur Datenbank */
$link= mysql_connect('localhost','root','') or die(mysql_error());
mysql_select_db('prozessor',$link) or die(mysql_error());
/** Es wird überprüft, ob der Projekteintrag bereits vorhanden ist */
$query = "SELECT * FROM projekte WHERE projekt = 'hossa' ";
$result = (mysql_query($query) or die(mysql_error()));
$anzahl = mysql_num_rows($result);
echo 'Datensaetze: ' . $anzahl;
Die Verbindung zur Datenbank funktioniert, aber ich erhalte immer die
"Warning: mysql_num_rows(): supplied argument is not a valid MySQL-result resource"-Fehlermeldung.
Auf http://de2.php.net/manual/de/function.mysql-num-rows.php wird im query der Datei-zeiger mit angegeben. Hat aber auch nichts geholfen.
Vielen Dank
Moin!
sehr einfache Aufgabe:
Ich möchte einen datenbank-INSERT davon abhängig machen, ob ein solcher Eintrag bereits vorhanden ist.
Dazu mache ich eine simple SELECT-abfrage nach dem entsprechenden Feld und möchte mit mysql_num_rows abfragen wieviele Ergebnisse diese lieferte.
Das ist die naheliegende Strategie, die aber in gewissen Szenarien, die du nicht ausschließen kannst, scheitern wird.
Stell dir einfach nur mal vor, zwei parallele Skriptaufrufe wollen die gleichen Daten insertieren. Dann kriegt die Skriptinstanz, die "zufällig" das erste SELECT abschickt, grünes Licht: Nix gefunden. Dann kommt die zweite Skriptinstanz und kriegt ebenfalls grünes Licht.
Skriptinstanz Nummer 1 schreibt jetzt das INSERT in die DB. Funktioniert alles, wie du es dir denkst. Und dann kommt Skript Nummer 2 und versucht dasselbe nochmal... BUMM. Wobei die Art und Weise des "Bumm" davon abhängt, was in so einem Doppelbelegungsfall in deiner DB passiert.
Die schlauere Alternative ist, durch einen Index sicherzustellen, dass garantiert keine doppelten Daten in einer Spalte, oder einer Spaltenkombination, eingefügt werden können - und dann einfach strikt INSERT zu benutzen, die DB wird sich mit einem Indexfehler melden, wenn der Datensatz schon vorhanden ist - ganz unabhängig von vorhergehenden SELECTs.
Es gibt auch die Variante, in dem Fall, dass das INSERT wegen Doppelbelegung scheitert, direkt ein UPDATE zu machen. Auf diese Weise implementiert man sehr einfach Aktualisierungen von bestehenden und ggf. auch neu dazukommenden Datensätzen. http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
Wenn das alles nichts ist, und tatsächlich ein SELECT mit nachfolgendem INSERT sein muß, läßt sich diese Konstruktion nur dann sicher verwenden, wenn du Transaktionen benutzt. Das macht die Sache aber gleich eine ganze Stufe komplexer.
- Sven Rautenberg
Vielen Dank euch allen,
habe das 'or die' weggelassen und das script funktioniert prima.
Auch wenn mir nicht ganz klar ist warum. Habe diese 'or die(mysql_error)'-konstruktion sonst immer benutzt und auch schon x-fach in diversen tutorials etc gelesen. Die bricht doch einfach nur das script ab und gibt den entsprechenden mysql-fehler aus, falls die anfrage aus irgendeinem Grund nicht ausgeführt wird, oder?
Werde es jetzt bei dieser Methode belassen, das script wird nur inhouse benutzt und im schlimmsten BUMM-fall taucht ein eintrag an anderer stelle doppelt auf.
Danke,
Paco
Vielen Dank euch allen,
habe das 'or die' weggelassen und das script funktioniert prima.
Auch wenn mir nicht ganz klar ist warum. Habe diese 'or die(mysql_error)'-konstruktion sonst immer benutzt und auch schon x-fach in diversen tutorials etc gelesen. Die bricht doch einfach nur das script ab und gibt den entsprechenden mysql-fehler aus, falls die anfrage aus irgendeinem Grund nicht ausgeführt wird, oder?
Werde es jetzt bei dieser Methode belassen, das script wird nur inhouse benutzt und im schlimmsten BUMM-fall taucht ein eintrag an anderer stelle doppelt auf.Danke,
Paco
Hi Paco,
wie jetzt oben bereits diskutiert:
der entscheidende Unterschied sind die Klammern.
$result = ($a or $b);
wertet den Ausdruck ($a or $b) aus, der ist TRUE, und das wird an $result uebergeben.
$result = $a or $b;
hingegen ist das, was wohl in den Tutorials steht, die Du meintest. Die Hierarchie ist hier anders - das ist gleichbedeutend mit
($result = $a) or $b;
d.h. $result wird der Wert von $a zugewiesen, und wenn $a != 0 ist, dann ist "or" zufrieden und gibt TRUE zurueck (was aber keinen interessiert, weil das Ergebnis von "or" nicht ausgewertet wird).
Lies Dir mal das hier durch, das wird Dich erhellen ;-)
Viele Gruesse,
der Bademeister
echo $begrüßung;
Auch wenn mir nicht ganz klar ist warum. Habe diese 'or die(mysql_error)'-konstruktion sonst immer benutzt und auch schon x-fach in diversen tutorials etc gelesen. Die bricht doch einfach nur das script ab und gibt den entsprechenden mysql-fehler aus, falls die anfrage aus irgendeinem Grund nicht ausgeführt wird, oder?
Ja, das hat sich verbeitet wie eine Seuche, weil es kurz und im Fehlerfall informativ ist. Für den Programmierer. Allerdings ist es alles andere als anwenderfreundlich und in den meisten Fällen auch völlig unnötig, sofort abzubrechen. Seine Verwendung zeigt nur, dass sich der Autor keine Gedanken um die Robustheit seiner Anwendung gemacht hat. Fehler treten nicht nur beim Programmieren auf. Auch im laufenden Betrieb bekommt man sie, wenn beispielsweise der Server gerade <del>seine Nachtruhe hält</del> z.B. wegen Backup kurzzeitig nicht ansprechbar ist.
Werde es jetzt bei dieser Methode belassen, das script wird nur inhouse benutzt und im schlimmsten BUMM-fall taucht ein eintrag an anderer stelle doppelt auf.
Das muss nicht sein. Sven hat doch bereits eine funktionierende, robuste und nicht allzu aufwendige Lösung genannt. Allerdings musst du dann doch eine ordentliche Fehlerbehandlung einbauen. Darauf zu verzichten ist (außerhalb des Labors) unter keinen Umständen eine gute Idee.
echo "$verabschiedung $name";
echo $begrüßung;
Ich möchte einen datenbank-INSERT davon abhängig machen, ob ein solcher Eintrag bereits vorhanden ist.
Dazu mache ich eine simple SELECT-abfrage nach dem entsprechenden Feld und möchte mit mysql_num_rows abfragen wieviele Ergebnisse diese lieferte.
Die bessere Strategie hat Sven ja schon erläutert. Ich beschränke mich deshalb auf das was du verkehrt machst, bzw. wie du es herausfinden kannst.
"Warning: mysql_num_rows(): supplied argument is not a valid MySQL-result resource"-Fehlermeldung.
Viele der mysql_*-Funktionen teilen einen aufgetretenen Fehler im Stillen mit, indem sie als Ergebnis ein false statt der sonst üblichen Ressourcen-Kennung liefern. false ist jedoch für die nachfolgende mysql_*-Funktion kein gültiges Argument, weswegen du von PHP eine Warnung bekommst.
$result = (mysql_query($query) or die(mysql_error()));
$anzahl = mysql_num_rows($result);
Warum er allerdings hier auftritt ist mir im Moment ein Rätsel, denn eigentlich hätte das die() anschlagen müssen. Bist du sicher, dass das die richtige Stelle zur Meldung ist? Wenn ja, dann mach bitte mit var_dump($result) eine Kontrollausgabe.
Auf http://de2.php.net/manual/de/function.mysql-num-rows.php wird im query der Datei-zeiger mit angegeben. Hat aber auch nichts geholfen.
Dateizeiger? Du meinst wohl die Ressourcenkennung der Verbindung. Wenn der Parameter nicht angegeben ist, suchen sich die mysql_*-Funktionen eine offene Verbindung. Bei einer einzigen Verbindung im Script ist es kein Problem, den Parameter wegzulassen, aber auch kein Beinbruch, wenn man ihn trotzdem der Ordnung halber mit angibt.
Übrigens: die() ist die zweitschlechteste aller Fehlerreaktionen (gleich nach Ignorieren). Besser ist es, auf den Fehler mit einer Fallunterscheidung zu reagieren und das Script ordentlich zu Ende zu bringen. Dabei sollte dem Anwender eine Meldung ausgegeben werden, die ihm was nützt. Sie könnte ihm Alternativen aufzeigen, wie er trotzdem noch zum Ziel kommt. Der Fehlermeldungstext von MySQL nützt dem Anwender nichts. Denjenigen, die die Information aus der Fehlermeldung auszunutzen wissen, will man diese Information nicht geben.
echo "$verabschiedung $name";
Das Problem ist die Zeile
$result = (mysql_query($query) or die(mysql_error()));
das ist etwas zu gewagt. Der Operator "or" gibt Dir einen boolschen Wert zurück. Eine Anweisung der Form
$result = ($a or $b);
setzt $result auf TRUE (und nicht auf $a), wenn $a != 0 ist. Und TRUE ist sicher keine gültige mysql-Ressource.
Etwas merkwürdig ist die Konstruktion noch aus einem anderen Grund: die Funktion die() hat keinen Rückgabewert und ist somit kein Ausdruck. "or" will aber zwei Ausdrücke auswerten.
Jetzt ist das natürlich
aber eine Funktion ohne definierten Rückgabewert sollte nicht als Ausdruck ausgewertet werden, sagt mir mein Sinn für PHP-Ästhetik.
Viele Grüße
der Bademeister
echo $begrüßung;
Das Problem ist die Zeile
$result = (mysql_query($query) or die(mysql_error()));
das ist etwas zu gewagt. Der Operator "or" gibt Dir einen boolschen Wert zurück. Eine Anweisung der Form
$result = ($a or $b);
setzt $result auf TRUE (und nicht auf $a), wenn $a != 0 ist. Und TRUE ist sicher keine gültige mysql-Ressource.
Die Klammern kamen mir auch spanisch vor, hab sie aber nicht direkt als Ursache vermutet. Es ist jedoch tatsächlich so, dass durch die Klammern das Ergebnis des Ausdrucks nach boolean umgewandelt wird. Lässt man die Klammern weg bekommt man das gewünschte Ergebnis: eine Ressourcenkennung.
Etwas merkwürdig ist die Konstruktion noch aus einem anderen Grund: die Funktion die() hat keinen Rückgabewert und ist somit kein Ausdruck. "or" will aber zwei Ausdrücke auswerten.
Nein, das will es nicht in jedem Fall. Wenn das Ergebnis bereits durch Auswertung eines Operanden feststeht, dann wird der zweite nicht mehr ausgewertet. Wenn bei einem or der erste Teilausdruck bereits true ergeben hat, dann ändert der zweite am Ergebnis nichts mehr. Das gleiche gilt für and, da aber für false. Der Begriff dazu lautet Kurzschlussverfahren.
Wenn das mysql_query() also einen Wert zurückliefert, der als true angesehen wird, dann interessiert das was die Funktion die() macht oder zurückgibt nicht mehr.
Jetzt ist das natürlich
- erstens hier egal, weil die() ggf. das Skript ohnehin beenden würde, bevor "or" ausgewertet wird
- und zweitens auch nicht ganz richtig, weil eine Funktion ohne definierten Rückgabewert technisch gesehen dann glaube ich NULL zurückgibt, was von "or" ausgewertet werden kann, so dass es in der Praxis funktionieren würde,
Da im Gutfall nichts ausgeführt wird, ist es auch egal, ob oder was zurückgegeben würde. Doch ja, der Rückgabewert einer Funktion ohne explizites return ist null. Allerdings sind "die" und "exit" genaugenommen keine Funktionen sondern Sprachkonstrukte.
aber eine Funktion ohne definierten Rückgabewert sollte nicht als Ausdruck ausgewertet werden, sagt mir mein Sinn für PHP-Ästhetik.
Es geht bei Konstrukten dieser Art nicht (nur) um ein Ergebnis sondern um die Ausführung oder Nicht-Ausführung des zweiten Teilausdrucks. Diese Konstrukte findet man auch häufig in Shell-Scripten. Statt eines mehrzeiligen if-bedingung-then notiert man es hintereinander und nutzt die Eigenschaften das Kurzschlussverfahren.
echo "$verabschiedung $name";
Hi $name,
Die Klammern kamen mir auch spanisch vor, hab sie aber nicht direkt als Ursache vermutet. Es ist jedoch tatsächlich so, dass durch die Klammern das Ergebnis des Ausdrucks nach boolean umgewandelt wird. Lässt man die Klammern weg bekommt man das gewünschte Ergebnis: eine Ressourcenkennung.
Das Ergebnis eines "or"-Ausdrucks ist immer boolean, da wird nix umgewandelt. Nur hat eben "=" einen hoeren Rang als "or", d.h. wenn Du die Klammern weglaesst, also
$result = $a or $b;
dann wird quasi
($result = $a) or $b;
ausgefuehrt, und die Zuweisung an $result hat mit dem Ergebnis von "or" nix zu tun.
Etwas merkwürdig ist die Konstruktion noch aus einem anderen Grund: die Funktion die() hat keinen Rückgabewert und ist somit kein Ausdruck. "or" will aber zwei Ausdrücke auswerten.
Nein, das will es nicht in jedem Fall. Wenn das Ergebnis bereits durch Auswertung eines Operanden feststeht, dann wird der zweite nicht mehr ausgewertet. Wenn bei einem or der erste Teilausdruck bereits true ergeben hat, dann ändert der zweite am Ergebnis nichts mehr. Das gleiche gilt für and, da aber für false. Der Begriff dazu lautet Kurzschlussverfahren.
Ok, ich empfinde es zwar etwas als Vergewaltigung des logischen Operators "or", ihn als "tu dies oder tu das"-Statement zu benutzen, aber da gibts unterschiedliche Meinungen, das stimmt. So eine
mysql_connect(....) or die();
Konstruktion sieht man ja oefters mal sogar in Buechern. Ich wuerd das nicht machen, erstens aus obigen Gruenden, und zweitens, wie Du unten schon beschrieben hast, weil ein Fehler in der Datenbankverbindung kein Grund fuer ein Skript ist, gleich bedingungslosen Selbtmord zu begehen, anstatt das zu einem vernuenftigen Ende zu kommen.
Aber ich sehe ein, meine Bermerkung zur "Aesthetik" war nicht mehr als eine persoenliche Meinungsaeusserung. Wenn man das richtig verwendet, dann gehen solche "or"-Konstruktionen technisch natuerlich. Aber man muss halt wissen, was man tut, wie das urspruengliche Problem dieses Threads zeigt.
Viele Gruesse
der Bademeister
echo $begrüßung;
Die Klammern kamen mir auch spanisch vor, hab sie aber nicht direkt als Ursache vermutet. Es ist jedoch tatsächlich so, dass durch die Klammern das Ergebnis des Ausdrucks nach boolean umgewandelt wird. Lässt man die Klammern weg bekommt man das gewünschte Ergebnis: eine Ressourcenkennung.
Das Ergebnis eines "or"-Ausdrucks ist immer boolean, da wird nix umgewandelt. Nur hat eben "=" einen hoeren Rang als "or", d.h. wenn Du die Klammern weglaesst, also
$result = $a or $b;
dann wird quasi
($result = $a) or $b;ausgefuehrt, und die Zuweisung an $result hat mit dem Ergebnis von "or" nix zu tun.
Interessante Thematik. Da ich das erst nicht so recht glauben wollte, habe ich damit etwas experimentiert, und dabei auch gesehen, dass
$c = false or true;
if ($c) ...
nicht das gleiche ist wie
if (false or true) ...
Das sieht man schön an den folgenden Beispielen.
$a = 0 or 23;
var_dump($a);
Ergibt int(0), nicht 23. Trotzdem "wird die 23 ausgeführt", oder genauer gesagt: der zweite Teilausdruck, und das auch erst nachdem die Zuweisung erfolgte.
function foo($x) {
var_dump($x);
return 23;
}
$b = 42;
$b = 0 or foo($b);
var_dump($b);
Ergibt int(0) int(0). Das erste ist die Ausgabe von $x. Daraus folgt, das zu dem Zeitpunkt $b bereits 0 ist und nicht mehr 42, und es auch bleibt. Das Funktionsergebnis von foo() spielt keine Rolle.
echo "$verabschiedung $name";
Interessante Thematik. Da ich das erst nicht so recht glauben wollte, habe ich damit etwas experimentiert, und dabei auch gesehen, dass
$c = false or true;
if ($c) ...nicht das gleiche ist wie
if (false or true) ...
Natuerlich nicht, aus dem bereits besprochenen Grund mit der Klammerung:
$c = false or true;
entspricht
($c = false) or true;
Das Ergebnis von "or" ist in dem Fall zwar true, aber das wird nicht $c zugewiesen, sondern ueberhaupt nicht ausgewertet. Dasselbe passiert in allen Deinen Beispielen:
$b = 0 or foo($b);
entspricht
($b = 0) or foo($b);
das heisst $b wird gleich 0 gesetzt, und ($b = 0) liefert den Ausdruck 0 an "or", so dass auch foo($b) ausgefuehrt wird. Das hat aber nichts mit der Zuweisung an $b mehr zu tun. $b wurde vorher auf 0 gesetzt, und daher wird 0 an foo() uebergeben.
Viele Gruesse
der Bademeister