Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > de.comp.lang.php > #3551
| From | Thomas 'PointedEars' Lahn <PointedEars@web.de> |
|---|---|
| Newsgroups | de.comp.lang.php |
| Subject | Re: Problem mit PDO |
| Date | 2015-11-15 14:23 +0100 |
| Organization | PointedEars Software (PES) |
| Message-ID | <15739846.o4CBAyVrKO@PointedEars.de> (permalink) |
| References | <n283h2$e0d$1@news.albasani.net> <56479A45.3090901@arnowelzel.de> <n288g5$n4i$1@news.albasani.net> <n28d72$dge$1@dont-email.me> <n29j1k$705$1@news.albasani.net> |
Peter Müller wrote:
> CREATE TABLE wiealt2 (
> `id` int(11) NOT NULL,
> `jahr` smallint(5) unsigned DEFAULT NULL,
> `baldwin` int(10) unsigned DEFAULT NULL)
> ENGINE=MyISAM DEFAULT CHARSET=utf8;
>
> INSERT INTO `wiealt2` (`id`, `jahr`, `baldwin`) VALUES
> (1, 1700, NULL),
> (10, 1810, 11),
> (11, 1811, 12),
> (12, 1812, 13),
> (13, 1813, 14),
> (14, 1814, 15),
> (15, 1815, 16),
> (16, 1816, 17),
> (17, 1817, 18),
> (18, 1818, 19),
> (19, 1819, NULL),
> (99, 1899, NULL);
>
> $firma = 'baldwin';
> $nummer = '15';
>
> $query1 = "SELECT max(jahr) as maxjahr FROM wiealt2 WHERE :firma <=
> :nummer";
> $stmt = $dbmerz -> prepare($query1);
> $stmt -> bindValue(':firma', $firma, PDO::PARAM_STR);
> $stmt -> bindValue(':nummer', $nummer, PDO::PARAM_INT);
> $stmt -> execute();
> $result1 = $stmt->fetchAll(PDO::FETCH_OBJ);
> if($result1)
> {
> $min=$result1[0]->maxjahr;
> var_dump($result1);
> }
> $query2 = "SELECT min(jahr) as minjahr FROM wiealt2 WHERE :firma >
> :nummer"; $stmt = $dbmerz -> prepare($query2);
> $stmt -> bindValue(':firma', $firma, PDO::PARAM_STR);
> $stmt -> bindValue(':nummer', $nummer, PDO::PARAM_INT);
> $stmt -> execute();
> $result2 = $stmt->fetchAll(PDO::FETCH_OBJ);
> if($result2)
> {
> $max=$result2[0]->minjahr;
> var_dump($result2);
> }
> print "<p>Nummer = $nummer; Firma = $firma; Min = $min, Max = $max.</p>";
>
> Ausgabe: array(1) { [0]=> object(stdClass)#86 (1) { ["maxjahr"]=> NULL }
> } array(1) { [0]=> object(stdClass)#87 (1) { ["minjahr"]=> string(4)
> "1700" } }
>
> Nummer = 15; Firma = baldwin; Min = , Max = 1700.
>
> SQL-Ausgabe ist aber dagegen:
> mysql> SELECT max(jahr) as maxjahr FROM wiealt2 WHERE baldwin <= 15;
> +---------+
> | maxjahr |
> +---------+
> | 1814 |
> +---------+
> 1 row in set (0.01 sec)
> mysql> SELECT min(jahr) as minjahr FROM wiealt2 WHERE baldwin > 15;
> +---------+
> | minjahr |
> +---------+
> | 1815 |
> +---------+
> 1 row in set (0.00 sec)
>
> Der PHP-Code liefert also NULL, 1700, SQL liefert 1814,1815 auf dieselbe
> Abfrage. Mir scheint, die WHERE-Abfrage wird hier verworfen. Wieso?
Es sind _nicht_ dieselben Abfragen und die WHERE-_Bedingung_ der _SELECT_-
Abfrage wird höchstens teilweise verworfen. Denn:
In Prepared Statements (PSs) mindestens mit mysqli und PDO_MySQL können
Namen keine ersetzten Werte sein (kann BTW in einer Frage in der ZCE-Prüfung
vorkommen, siehe Trainingsmaterial).
Denn Deine PSs
SELECT max(jahr) as maxjahr FROM wiealt2 WHERE :firma <= :nummer
bzw.
SELECT min(jahr) as minjahr FROM wiealt2 WHERE :firma > :nummer
sind mit den verwendeten Wertbindungen äquivalent zu
SELECT MAX(`jahr`) AS `maxjahr` FROM `wiealt2` WHERE 'baldwin' <= 15;
bzw.
SELECT MIN(`jahr`) AS `minjahr` FROM `wiealt2` WHERE 'baldwin' > 15;
Es wird also nicht mit dem Wert der Feldes in der Spalte `baldwin` des
jeweiligen Datensatzes, sondern mit dem fixen String-Wert 'baldwin'
verglichen. Da das nicht sinnvoll ist (der zweite Operand ist eine Zahl),
wird der String gekürzt. Debugging-Beispiel mit Deiner Tabelle (bei mir
`tmp`:
,----
| $ mysql -u root -p
| Enter password:
| Welcome to the MySQL monitor. Commands end with ; or \g.
| Your MySQL connection id is 106
| Server version: 5.6.25-3 (Debian)
|
| Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights
| reserved.
|
| Oracle is a registered trademark of Oracle Corporation and/or its
| affiliates. Other names may be trademarks of their respective
| owners.
|
| Type 'help;' or '\h' for help. Type '\c' to clear the current input
| statement.
|
| mysql> use tmp;
| Reading table information for completion of table and column names
| You can turn off this feature to get a quicker startup with -A
|
| Database changed
| mysql> SELECT * FROM `tmp`;
| +----+------+---------+
| | id | jahr | baldwin |
| +----+------+---------+
| | 1 | 1700 | NULL |
| | 10 | 1810 | 11 |
| | 11 | 1811 | 12 |
| | 12 | 1812 | 13 |
| | 13 | 1813 | 14 |
| | 14 | 1814 | 15 |
| | 15 | 1815 | 16 |
| | 16 | 1816 | 17 |
| | 17 | 1817 | 18 |
| | 18 | 1818 | 19 |
| | 19 | 1819 | NULL |
| | 99 | 1899 | NULL |
| +----+------+---------+
| 12 rows in set (0.00 sec)
|
| mysql> SELECT * FROM `tmp` WHERE 'baldwin' <= 15;
| +----+------+---------+
| | id | jahr | baldwin |
| +----+------+---------+
| | 1 | 1700 | NULL |
| | 10 | 1810 | 11 |
| | 11 | 1811 | 12 |
| | 12 | 1812 | 13 |
| | 13 | 1813 | 14 |
| | 14 | 1814 | 15 |
| | 15 | 1815 | 16 |
| | 16 | 1816 | 17 |
| | 17 | 1817 | 18 |
| | 18 | 1818 | 19 |
| | 19 | 1819 | NULL |
| | 99 | 1899 | NULL |
| +----+------+---------+
| 12 rows in set, 1 warning (0.00 sec)
|
| mysql> SHOW WARNINGS;
| +---------+------+---------------------------------------------+
| | Level | Code | Message |
| +---------+------+---------------------------------------------+
| | Warning | 1292 | Truncated incorrect DOUBLE value: 'baldwin' |
| +---------+------+---------------------------------------------+
| 1 row in set (0.00 sec)
|
| mysql> SELECT MAX(`jahr`) FROM `tmp` WHERE 'baldwin' <= 15;
| +-------------+
| | MAX(`jahr`) |
| +-------------+
| | 1899 |
| +-------------+
| 1 row in set, 1 warning (0.00 sec)
|
| mysql> SELECT MIN(`jahr`) FROM `tmp` WHERE 'baldwin' > 15;
| +-------------+
| | MIN(`jahr`) |
| +-------------+
| | NULL |
| +-------------+
| 1 row in set, 1 warning (0.00 sec)
`----
[Dieselben Ergebnisse erhalte ich auch über PHP. Weshalb bei Dir angeblich
für das Ergebnis der ersten Abfrage NULL und für das der zweiten 1700
geliefert wird statt 1899 und NULL, ist mir noch nicht klar. Klar ist aber,
dass die Abfragen so nicht funktionieren *können*.]
Du musst stattdessen den Spaltennamen mit String-Konkatenation oder
sprintf() in die Abfrage einbauen und solltest ihn dann geeignet (MySQL:
mindestens mit `…`) escapen, so wie Du es anfangs getan hast. (Da man das
immer wieder braucht, schreibt man sich dafür entweder eine Datenbank-
Klasse, so wie ich es für mein PHPX-Framework [1] für die ECMAScript Support
Matrix [2] getan habe, oder verwendet zum Beispiel die Datenbank-Klassen des
Zend Framework 2 [3].)
Für eine einmalige Abfrage kannst Du übrigens PDOStatement::execute() ein
assoziatives Array aus Werten übergeben. Wertbindung ist nur
sinnvoll/nötig, wenn die ansonsten gleiche Abfrage mehrfach mit
unterschiedlichen Werten ausgeführt wird. Und dann ist es nur sinnvoll, das
jeweilige PDOStatement *einmal* zu erstellen und nur die Wertbindung zu
ändern oder Parameter zu binden (PDOStatement::bindParam()) und nur die
Werte der gebundenen Variablen zu ändern.
Bezüglich Codestil rate ich Dir:
- Keine Zeilen über die 80. Spalte hinaus (für Usenet: nicht über die 76.
Spalte hinaus)
- Nur Operatoren werden immer von Whitespace umschlossen. “->” ist i.e.S.
in PHP *kein* Operator¹:
<http://php.net/manual/en/language.operators.php>
- “if” ist kein Funktionsbezeichner, sondern das Schlüsselwort einer
Steueranweisung; nach solchen steht immer ein Leerzeichen:
if ($result1) …
- Bei Anweisungsblöcken wird nicht die erste geschweifte Klammer eingerückt,
sondern nur der Inhalt des Blocks.
- Ganz allgemein: Whitespace wird konsistent verwendet. Also zum Beispiel
nicht
$dbmerz -> prepare($query2)
und dann wieder
$stmt->fetchAll(PDO::FETCH_OBJ)
oder mal
$stmt = $dbmerz -> prepare($query2);
und dann wieder
$max=$result2[0]->minjahr;
Mit einer PHP-Entwicklungsumgebung wie zum Beispiel Eclipse PDT oder
Zend Studio wird das einfacher.
- Alle Schlüsselwörter und Bezeichner eingebauter Funktionen in
SQL-Anweisungen werden durchgängig gross geschrieben; andere Namen
werden durchgängig so geschrieben, wie sie erstellt wurden
(Empfehlung: Kleinschreibung mit Unterstrich) und gequotet (“MIN(`jahr`).
- Namen von Tabellen sollten Entitäten beschreiben und optimal auf Englisch
sein, also nicht “wiealt2”, sondern “company_age”. Bezüglich Englisch
gilt dasselbe für Namen von Datenbanken, Spalten und Stored Procedures.
Ein leicht lesbarer Quelltext trägt viel dazu bei, Fehler im Quelltext zu
finden und auszumerzen. Das gilt sowohl für den Fall, dass Du Fehler in
Deinem Quelltext finden musst als auch, dass andere Deinen Quelltext
verstehen sollen.
Allerdings macht Deine Datenbank allgemein einen falsch strukturierten
Eindruck: “baldwin” ist anscheinend der Name einer Firma (Du vergleichst mit
einem Wert mit dem Platzhalter “:firma”); eine Spalte namens “baldwin”
sollte es deshalb gar nicht geben, sondern 'baldwin' bzw. die ID von
“baldwin” sollte ein *Wert* in einem *Feld* einer Spalte sein. Das könnte
man weiter in <news:de.comp.datenbanken.mysql> diskutieren.
[1] <http://PointedEars.de/wsvn/PHPX/trunk/Db/>
[2] <http://PointedEars.de/es-matrix/>
[3]
<http://framework.zend.com/apidoc/2.4/classes/Zend.Db.Adapter.Platform.Mysql.html>
_________
¹ Ja, ich kenne T_OBJECT_OPERATOR und
<http://php.net/manual/en/language.oop5.properties.php>
--
PointedEars
Zend Certified PHP Engineer
Twitter: @PointedEars2
Please do not cc me. / Bitte keine Kopien per E-Mail.
Back to de.comp.lang.php | Previous | Next — Previous in thread | Next in thread | Find similar
Problem mit PDO Peter Müller <peter.mueller@c-major.de> - 2015-11-14 20:54 +0100
Re: Problem mit PDO Arno Welzel <usenet@arnowelzel.de> - 2015-11-14 21:32 +0100
Re: Problem mit PDO Peter Müller <peter.mueller@c-major.de> - 2015-11-14 22:19 +0100
Re: Problem mit PDO Markus Grob <snoopy@ilnet.ch> - 2015-11-14 23:41 +0100
Re: Problem mit PDO Peter Müller <peter.mueller@c-major.de> - 2015-11-15 10:25 +0100
Re: Problem mit PDO Thomas Mlynarczyk <thomas@mlynarczyk-webdesign.de> - 2015-11-15 12:42 +0100
Re: Problem mit PDO Thomas Mlynarczyk <thomas@mlynarczyk-webdesign.de> - 2015-11-15 13:03 +0100
Re: Problem mit PDO Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2015-11-15 14:26 +0100
Re: Problem mit PDO Thomas Mlynarczyk <thomas@mlynarczyk-webdesign.de> - 2015-11-15 16:32 +0100
Re: Problem mit PDO Peter Müller <peter.mueller@c-major.de> - 2015-11-15 14:37 +0100
Re: Problem mit PDO Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2015-11-15 15:30 +0100
Re: Problem mit PDO Peter Müller <peter.mueller@c-major.de> - 2015-11-15 19:26 +0100
Re: Problem mit PDO Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2015-11-15 21:10 +0100
Re: Problem mit PDO Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2015-11-15 14:23 +0100
Re: Problem mit PDO Peter Müller <peter.mueller@c-major.de> - 2015-11-15 14:39 +0100
Re: Problem mit PDO Arno Welzel <usenet@arnowelzel.de> - 2015-11-16 08:43 +0100
Re: Problem mit PDO Peter Müller <peter.mueller@c-major.de> - 2015-11-16 21:23 +0100
Re: Problem mit PDO Thomas Mlynarczyk <thomas@mlynarczyk-webdesign.de> - 2015-11-15 13:09 +0100
Re: Problem mit PDO Markus Grob <snoopy@ilnet.ch> - 2015-11-17 09:48 +0100
Re: Problem mit PDO Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2015-11-17 20:13 +0100
Re: Problem mit PDO Stefan+Usenet@Froehlich.Priv.at (Stefan Froehlich) - 2015-11-17 22:09 +0000
Re: Problem mit PDO Markus Grob <snoopy@ilnet.ch> - 2015-11-20 21:59 +0100
csiph-web