Bei Prepared Statement Zeichen ersetzen

exzel

SQL-Guru
Beiträge
170
Hallo zusammen,

derzeit probiere ich gerade Prepared Statements aus. Bei einer gewöhnlichen INSERT oder UPDATE Anweisung kann ich durch REPLACE ein Zeichen durch ein anderes ersetzen. In meinem Fall handelt es sich um ein HTML Eingabefeld (Beitragsfeld), in dem ein Beitrag mit Tausender- und Dezimaltrennzeichen eingegeben werden kann. MySQL lehnt ein Komma ab.

Im folgenden Thread wurde mir der Tip mit Replace gegeben.

https://www.datenbankforum.com/threads/in-insert-anweisung-zeichen-ersetzen.408/

Soweit so gut. Doch leider klappt das die Replace Anweisung bei den Prepared Statements nicht. Oder vielleicht mache ich was falsch. Hier der Code für den Button zum Übernehmen der eingetragenen Ziel auf der HTML-Seite.

Code:
if($_POST['uebernehmen'])
{
    $stmt=$mysqli->prepare($insertziele);
    $stmt->bind_param("sdddddddddddddd",
    $uid,
    $_POST['ziel1'],
    $_POST['ziel2'],
    $_POST['ziel3'],
    $_POST['ziel4'],
    $_POST['ziel5'],
    $_POST['ziel6'],
    $_POST['ziel7'],
    $_POST['ziel1'],
    $_POST['ziel2'],
    $_POST['ziel3'],
    $_POST['ziel4'],
    $_POST['ziel5'],
    $_POST['ziel6'],
    $_POST['ziel7']);
    $stmt->execute();
}

Code:
$insertziele="INSERT INTO zielema (jahr, id_betreuer, ziel1, ziel2, ziel3, ziel4, ziel5, ziel6, ziel7) VALUES (2013,?,?,?,?,?,?,?,?)
ON DUPLICATE KEY UPDATE
ziel1= REPLACE(REPLACE(?, '.' , ''), ',' , '.'),
ziel2= ?,
ziel3= ?,
ziel4= ?,
ziel5= ?,
ziel6= ?,
ziel7= ?;";

Die innere Replace Funktion löscht beim eingetragenen Wert den Punkt, während die äußere das Komma durch den Punkt ersetzt. Somit ist der Wert SQL tauglich und korrekt gespeichert. Damit die Ausgabe wieder Punkt und Komma anzeigt habe ich über PHP das Ausgabefeld formatiert.

Aber die Nachkommastellen werden immer durch 0 ersetzt. Also aus 555,55 wird beim ersten Übernehmen 555,00. Was läuft falsch?

Gruß und Dank!
 
Werbung:

akretschmer

Datenbank-Guru
Beiträge
9.731
Hallo zusammen,

derzeit probiere ich gerade Prepared Statements aus. Bei einer gewöhnlichen INSERT oder UPDATE Anweisung kann ich durch REPLACE ein Zeichen durch ein anderes ersetzen. In meinem Fall handelt es sich um ein HTML Eingabefeld (Beitragsfeld), in dem ein Beitrag mit Tausender- und Dezimaltrennzeichen eingegeben werden kann. MySQL lehnt ein Komma ab.

An der Stelle kann man mit lesen aufhören. Wie die DB etwas speichert, ist das eine. Dazu nutzt sie das, was sie kann. Wie es ausgegeben wird, ist eine andere Geschichte. Dezimaltrennzeichen, Tausender-Dingens, 12- oder 24 - Stunden - Darstellung, Dezember oder December - alles für die interne Speicherung egal. Dazu gibt es (in richtigen Datenbanken zumindest) passende Ausgabe-Formatier-Funktionen. Nutze diese, und gut ist.
 

exzel

SQL-Guru
Beiträge
170
Hallo,

das habe ich nicht ganz verstanden.

Also in das HTML-Feld wird 12345,12 geschrieben. Die Datenbank würde die Zahl so nicht anerkennen. Die Spalte in der Datenbank ist nämlich vom Typ decimal. Somit verarbeitet mysql diese Zahl nicht korrekt. Was soll die korrekte Ausgabe-Formatier-Funktionen helfen?

Gruß und Dank!
 

akretschmer

Datenbank-Guru
Beiträge
9.731
Hallo,

das habe ich nicht ganz verstanden.

Also in das HTML-Feld wird 12345,12 geschrieben. Die Datenbank würde die Zahl so nicht anerkennen. Die Spalte in der Datenbank ist nämlich vom Typ decimal. Somit verarbeitet mysql diese Zahl nicht korrekt. Was soll die korrekte Ausgabe-Formatier-Funktionen helfen?

Gruß und Dank!


Ah, ich war im ersten Post vom Schluß her davon ausgegangen, daß es Dir um die Ausgabe mit Gruppen-und Dezimaltrenner ging.

Also um:
Code:
test=# create table excel (f double precision);
CREATE TABLE
test=*# insert into excel values(1);
INSERT 0 1
test=*# insert into excel values(12345.12);
INSERT 0 1
test=*# select to_char(f, '99G999D99') from excel;
  to_char
------------
  1,00
  12.345,12
(2 rows)

test=*# show lc_numeric;
 lc_numeric
-------------
 de_DE.UTF-8
(1 row)

test=*# set lc_numeric to 'en_US.UTF-8';
SET
test=*# select to_char(f, '99G999D99') from excel;
  to_char
------------
  1.00
  12,345.12
(2 rows)

Aber Du willst das ja vor der Eingabe umwandeln, oder?

Code:
test=*# set lc_numeric to 'de_DE.UTF-8';
SET
test=*# select to_number('12345,67','999999D99');
 to_number
-----------
  12345.67
(1 row)


Ich weiß nicht, ob MySQL und/oder PHP da schon passende Funktionen her haben.

Der Insert klappt? Wass steht denn in der DB dann drin, sind da noch die Nachkommastellen, oder fehlen sie da schon?
 

exzel

SQL-Guru
Beiträge
170
Hallo und danke für die Rückmeldungen!

Also die Spalte ist mit decimal(11,2) angelegt. Der Insert bzw. Update klappt bei folgendem Code

PHP:
....
ziel1= REPLACE(REPLACE(?, '.' , ''), ',' , '.'),
.....
(siehe oben) folgendermaßen.

Ich gebe 5555,55 ein und führe den Query aus. Es wird dann 5555,00 in der DB gespeichert. Auch bei mehrfacher Ausführung. Die zwei Nullen werden in der DB angezeigt.

Ändere ich den obigen Code auf

PHP:
....
ziel1=?,
.....

und wiederhole das ganze mehrfach wird aus 5555,55 ->5555,00->5,56->5,00.

Vollständigerweise muss ich sagen, dass die Ausgabe über PHP formatiert wird.
PHP:
echo number_format($zielefeld['ziel1'], 2 , ',' , '.')


Gestern habe ich das ganze nochmals ohne Prepared Statements probiert.

Code:
$updatetest="UPDATE zielema SET ziel1 = REPLACE(REPLACE('{$_POST['ziel1 ']}', '.' , ''), ',' , '.');";

So wird einwandfrei die Zahl korrekt umgewandelt und gespeichert in der DB. Warum das in dem Prepared Statement nicht funktioniert ist mir ein Rätsel. Im schlimmsten Fall muss ich halt die Formatierung über PHP machen. Oder gibt es noch Lösungsansätze über die DB?

Gruß und Dank!
 

akretschmer

Datenbank-Guru
Beiträge
9.731
Hallo und danke für die Rückmeldungen!

Aus dem ersten Post:

Code:
$stmt->bind_param("sdddddddddddddd", $uid, $_POST['ziel1'], $_POST['ziel2'],

Du definierst die Parameter als 'd', die Werte in POST['ziel1'] etc. sind aber Strings, ohne jetzt viel Ahnung von PHP zu haben denke ich, das geht so schon nicht.

Im ersten Post scheint es, als ob es nicht gewollt ist, daß da die Nachkommastellen zu 0 werden, jetzt schreibst aber:

"Der Insert bzw. Update klappt bei folgendem Code" ...
"Ich gebe 5555,55 ein und führe den Query aus. Es wird dann 5555,00 in der DB gespeichert. Auch bei mehrfacher Ausführung. Die zwei Nullen werden in der DB angezeigt."

Klingt für mich, als ob das genau das ist, was Du willst.


Ich würde ja direkt mit SQL ein Prepare auf der DB machen, sagen, daß da ein String kommt, und in der DB mit to_number() arbeiten.

Code:
test=# create table x(val double precision);
CREATE TABLE
test=*# prepare insert_x as insert into x (val) values (to_number($1, '9999999D99'));
PREPARE
test=*# execute insert_x('12345,67');
INSERT 0 1
test=*# select * from x;
  val
----------
 12345.67
(1 row)

Aber ich kenne MySQL und mysqli als PHP-Schnittstelle zu wenig, um da einen richtigen Weg Dir vorschlagen zu können.
 

exzel

SQL-Guru
Beiträge
170
Also so wie ich das verstanden habe, muss ich den Typ im Prepared Statement angeben, der in der Datenbankspalte hinterlegt ist. In der Datenbank sind die Ziele als decimal(11,2) also muss ich auch d im Prepared Statement angeben. Und die Ziele weren auch also Kommazahlen angegeben. So müsste es doch passen, oder?

Trotzdem danke!
 

akretschmer

Datenbank-Guru
Beiträge
9.731
Also so wie ich das verstanden habe, muss ich den Typ im Prepared Statement angeben, der in der Datenbankspalte hinterlegt ist. In der Datenbank sind die Ziele als decimal(11,2) also muss ich auch d im Prepared Statement angeben.
Denke ich mal, ja.

Und die Ziele weren auch also Kommazahlen angegeben. So müsste es doch passen, oder?

Trotzdem danke!

Nee, weil dann paßt der Typ nicht. Ich weiß nicht, wie man das in PHP löst. Bei meiner alten Arbeit hab ich etwas mit PHP gespielt, hier und jetzt nicht mehr.
 

exzel

SQL-Guru
Beiträge
170
Bist du dir sicher, dass der Typ nicht passt. Also obwohl eine Dezimalzahl in das HTML-Eingabefeld eingegeben war, ist der Typ decimal im Prepared Statement falsch. Warum?
 

akretschmer

Datenbank-Guru
Beiträge
9.731
Bist du dir sicher, dass der Typ nicht passt. Also obwohl eine Dezimalzahl in das HTML-Eingabefeld eingegeben war, ist der Typ decimal im Prepared Statement falsch. Warum?

Du denkst zu sehr deutsch. Ein String mit Komma wird nicht automatisch eine Zahl, nur weil hier bei uns das Komma der Dezimaltrenner ist.

Code:
test=# select '1234.56'::decimal;
 numeric
---------
 1234.56
(1 row)

Time: 40,536 ms
test=*# select '1234,56'::decimal;
ERROR:  invalid input syntax for type numeric: "1234,56"
LINE 1: select '1234,56'::decimal;
  ^
Time: 0,184 ms
test=*#

Auch wenn ich MySQL ned mag, das dürfte da exakt genauso sein (inhaltlich, CAST-Syntax ist da wohl anders. In PG ist decimal nur ein Synonym für numeric)
 

ukulele

Datenbank-Guru
Beiträge
4.702
Ich wüsste auch keinen Weg SQL beizubringen ein Komma als Dezimaltrennzeichen zu akzeptieren daher wäre meine erste Intuition auch das per replace() oder so zu wechseln.
 

exzel

SQL-Guru
Beiträge
170
Hallo,

ja, das dachte ich auch aber REPLACE funktioniert bei mir eben nicht in Kombination mit einem Prepared Statement. Bei einem gewöhnlichem Query schon. Keine Ahnung warum.
 
Werbung:

akretschmer

Datenbank-Guru
Beiträge
9.731
Hallo,

ja, das dachte ich auch aber REPLACE funktioniert bei mir eben nicht in Kombination mit einem Prepared Statement. Bei einem gewöhnlichem Query schon. Keine Ahnung warum.

Du kannst nicht direkt alles mit prepared Dinges machen, so z.B. auch nicht: select * from foo where id in (1,2,3), weil prepared heiß ja auch, daß die Anzahl der Parameter zum prepare-zeitpunkt feststeht. Wenn Du da also beim prepare mit ... id in (?) arbeitest und dann aber '1,2,3' übergibst, dann sind das plötzlich 2 Paraneter zu viel. Vermutlich passiert hier exakt dasselbe.
 
Oben