Discussion:
Float-Parameter mit ADOQuery auf MySQL
(zu alt für eine Antwort)
Lothar Armbrüster
2011-11-09 10:54:27 UTC
Permalink
Hallo NG,
ich habe gerade ein Problem mit einem Update einer MySQL-Tabelle. Ich
verwende D2010 und TADOQuery.
Folgenden SQL verwende ich für das Update:

update tabelle set
spalte=:SPALTE
where
id=:ID

Im Programm verwende ich folgenden Code:

var
wert :double;

...
wert := 0.25;

with ADOQuery_Update do
begin
Parameters.ParamByName('SPALTE').Value := wert;
Parameters.ParamByName('ID').Value := 1;
ExecSQL;
end;

Der Parameter SPALTE hat DataType ftFloat. Im ExecSQL bekomme ich eine
Exception mit der Meldung:

'[MySQL][ODBC 5.1 Driver][mysqld-5.5.13]Incorrect decimal value:
'0,25' for column 'Spalte' at row 1'.

Ich habe schon versucht, DecimalSeparator auf '.' zu setzen, aber das
hat nicht geholfen.
Was kann ich tun? Warum werden die Parameter nicht als Double
übergeben, sondern in Text gewandelt?
Muss ich die Parameter wirklich selbst als Text formatieren? Kann ich
in den ADO-Einstellungen etwas drehen?

Fragen über Fragen...

Lothar Armbrüster
Christian Gudrian
2011-11-09 16:37:31 UTC
Permalink
Post by Lothar Armbrüster
Muss ich die Parameter wirklich selbst als Text formatieren? Kann ich
in den ADO-Einstellungen etwas drehen?
Des Pudels Kern ist die Konvertierung des Variant-Wertes in eine String-Repräsentation, die in das SQL-Statement eingebaut werden kann. Intern werkelt da die API-Funktion VarBstrFromCy -- und die verwendet standardmäßig die Zahlenformatierung aus den Regionseinstellungen in der Systemsteuerung.

Ob und wie man die überschreiben kann, weiß ich nicht.

Christian
Christian Gudrian
2011-11-09 16:57:36 UTC
Permalink
Post by Christian Gudrian
Ob und wie man die überschreiben kann, weiß ich nicht.
Jetzt weiß ich's:

----------->8------------------------->8-----------------------------
function GetSystemDecimalSeparator: WideString;
var
L: Integer;
begin
L := GetLocaleInfo(GetUserDefaultLCID, LOCALE_SDECIMAL, nil, 0);
SetLength(Result, L);
GetLocaleInfo(GetUserDefaultLCID, LOCALE_SDECIMAL, PWideChar(Result), L);
end;

procedure SetSystemDecimalSeparator(const DS: WideString);
begin
SetLocaleInfo(GetUserDefaultLCID, LOCALE_SDECIMAL, PWideChar(DS));
end;

procedure TForm2.FormCreate(Sender: TObject);
var
V: Variant;
DS: WideString;
begin
DS := GetSystemDecimalSeparator;
SetSystemDecimalSeparator('hu');
try
V := 2.5;
Label1.Caption := V;
finally
SetSystemDecimalSeparator(DS);
end;
Label2.Caption := V;
end;
----------->8------------------------->8-----------------------------

Doch Vorsicht! Die Änderung ist systemweit und wirkt sich unmittelbar auf alle neuen (und vielleicht auch auf laufende) Prozesse aus.

Christian
Lothar Armbrüster
2011-11-10 16:40:11 UTC
Permalink
Post by Christian Gudrian
Post by Christian Gudrian
Ob und wie man die überschreiben kann, weiß ich nicht.
[...]
Post by Christian Gudrian
Doch Vorsicht! Die Änderung ist systemweit und wirkt sich unmittelbar auf alle neuen (und vielleicht auch auf laufende) Prozesse aus.
Christian
Das scheint mit dann doch ein Wenig der Overkill zu sein.
Ich habe jetzt einfach mal

Parameters.ParamByName('WERT').Value := FloatToStr(wert);

geschrieben, was ich mit DecimalSeparator steuern kann. Das hat ersma
den gewünschten Effekt. Ich find das allerdings immer noch unelegant.

Gennerell gilt sowieso: Varianten sind böse! ;-)

Trotzdem vielen Dank für Deine Ausführungen.

Und tschüss,
Lothar
--
Lothar Armbrüster | ***@t-online.de
Hauptstr. 26 |
65346 Eltville |
Burkhard Schneider
2011-11-10 07:50:24 UTC
Permalink
Post by Lothar Armbrüster
var
wert :double;
...
wert := 0.25;
with ADOQuery_Update do
begin
Parameters.ParamByName('SPALTE').Value := wert;
Parameters.ParamByName('ID').Value := 1;
ExecSQL;
end;
Probier mal
Parameters.ParamByName('SPALTE').AsFloat:= wert

Dann entfällt die Umwandlung in ein Variant wie bei Value. AsFloat sollte
sich dann um die korrekte Darstellung für die Query kümmern. Dafür gibt es
ja die ganzen Asxxx-Eigenschaften.

Bloß nichts an den Systemeinstellungen rumfummeln.

Gruß
Burkhard Schneider
Christian Gudrian
2011-11-10 09:08:23 UTC
Permalink
Post by Burkhard Schneider
Parameters.ParamByName('SPALTE').AsFloat:= wert
ParamByName.Value liefert Variant zurück, nicht TField. Letzteres formatiert die Gleitkommazahl mit FloatToStrF, was wiederum den Wert von DecimalSeparator berücksichtig.

Christian
Burkhard Schneider
2011-11-10 11:26:47 UTC
Permalink
Post by Christian Gudrian
Post by Burkhard Schneider
Parameters.ParamByName('SPALTE').AsFloat:= wert
ParamByName.Value liefert Variant zurück, nicht TField.
Letzteres formatiert die Gleitkommazahl mit FloatToStrF,
was wiederum den Wert von DecimalSeparator berücksichtig.
Sorry, da bin ich wohl auf die Besonderheit von ADOQuery hereingefallen.
Andere Queries arbeiten ja mit TParams anstatt TParameters. Und das
ParamByName von TParams hat im Gegensatz zum ParamByName von TParameters die
Eigenschaft AsFloat, um einem Parameter einen Gleitkommawert zuzuweisen. Hat
nichts mit TField zu tun.

Ich habe noch nicht so viel mit ADOQuery gearbeitet und hatte vorausgesetzt,
das es da genauso ist, wie bei den von mir eingesetzten Queries.

Gruß
Burkhard Schneider
Lesen Sie weiter auf narkive:
Loading...