MySQL: numerische Werte aus Tabelle lesen

Für Themen zu Datenbanken und Zugriff auf diese. Auch für Datenbankkomponenten.
Antworten
manfred.mader@gmx.de
Beiträge: 10
Registriert: Mo 6. Jul 2015, 09:09
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: 64Bit

MySQL: numerische Werte aus Tabelle lesen

Beitrag von manfred.mader@gmx.de »

Hallo zusammen!

Ich programmiere gerade eine MySQL-Anwendung, nämlich eine Art Kontoführung. Connect zum Server, Auswahl der Datenbank, Ausführen eines Selects und Anzeige der Ergebnisse in einer StringGrid, all das funzt schon gut. Nun taucht aber ein Problem auf, das mich inzwischen verzweifeln läßt (und auch intensive Suche im Forum und langwieriges Googeln bringt mich da nicht weiter :( Meine ganze Hoffnung liegt jetzt bei euch ...

Also, ich mache einen Select (mit mysql_query(socket, query)), stelle ihn mit mysql_store_result(socket) bereit, und lese ihn dann mit rowbuffer:=mysql_fetch_row Satz für Satz durch, dann kann ich über Index auf die einzelnen Felder des jeweiligen Datensatzes zugreifen und deren Inhalte z.B. mit einem writeln ausgeben. Das klappt auch. Diese Felder sind - soweit glaube ich, es verstanden zu haben, vom Typ AnsiString. Nun gibt es ja aber auch Felder, deren Inhalt ihrer Natur nach numerisch sind. Konkret: Ich habe ein Feld namens sh, dessen Inhalt 'S' oder 'H' sein kann - für "Soll" oder "Haben". Ein weiteres Feld namens Betrag enthält - uberraschenderweise - einen Betrag. Die Aufgabe ist nun, bein Durchlesen der Datensätze jedesmal, wenn sh='S' ist, den Betrag mit -1 zu multiplizieren. Dazu muß ich (jedenfalls sehe ich das so - belehrt mich gern eines Besseren ...), daß ich
1. das Feld Betrag von AnsiString in irgendwas numerisches (real, float, double, ...) konvertieren muß,
2. es mit -1 multiplizieren muß, und dann zwecks Anzeige dieses Ding
3. wieder in was anzeigbares (String, PChar, AnsiString oder was weiß ich ...) zurückkonvertieren muß.
Und genau das krieg ich nicht hin ...
Icch hab's schon mit 1000 verschiedenen Typkonvertierungen hin und her versucht, aber nur Fehlermeldungen geerntet. Die Frage ist eben schlicht: Wie kann ich einen AnsiString (?) in ein "rechenfähiges" Format konvertieren (und zurück)?

Hier das Programm, wie es bis jetzt aussieht (Unwichtiges habe ich rausgeschmissen, um euch nicht unnötig zu strapazieren ...)

Ganz herzlichen Dank schon mal!
Manfred





Code: Alles auswählen

program mysqltest;
 
//******************************************************************************
//**  "Einfaches Programm" zum Testen von MySQL-Anbindungen.
//**   Mit eigener Unit-Datei.
//******************************************************************************
 
 
//------------------------------------------------------------------------------
//  Declarations
//------------------------------------------------------------------------------
 
uses
  mysql4, mmaSQL;
 
Const
  DBName : Pchar  = 'xxxx';
  DBUser : PChar  = 'yyyy';
  DBPass : PChar  = 'zzzzzzzz';
  Query  : PChar  = 'select * from r10d00 where konto="GITO" order by buchid limit 2';
var
  sock   : PMYSQL;
  recbuf : PMYSQL_RES;
 
//------------------------------------------------------------------------------
 
begin
  startmeldung(Signum);
 
  sock := dbConnect(DBUser, DBPass);        // Connecten
  dbAuswaehlen(sock, DBName);               // Datenbank auswählen (xxxx)
  queryAusfuehren(sock, Query);             // Query nun ausführen
  recbuf := queryResultBereitstellen(sock); // Ergebnis in recbuf bereitstellen
  ergebnisdatensaetze_anzeigen(recbuf);
end.
 
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 
unit mmasql;
 
interface
 
uses
  Classes, SysUtils, MySQL4;
 
function  dbConnect(User, Password: PChar) : PMYSQL;
procedure dbAuswaehlen(socket: PMYSQL; datenbankname: PChar);
procedure queryAusfuehren(socket: PMYSQL; Query: PChar);
function  queryResultBereitstellen(socket: PMYSQL): PMYSQL_RES;
procedure ergebnisdatensaetze_anzeigen(recordbuffer: PMYSQL_RES);
procedure aufraeumen(socket: PMYSQL; recordbuffer: PMYSQL_RES);
 
//******************************************************************************
 
implementation
 
var qmysql : TMYSQL;
 
//------------------------------------------------------------------------------
function dbConnect(User, Password: PChar) : PMYSQL;
var socket : PMYSQL;
begin
  mysql_init(PMySQL(@qmysql));
  socket :=  mysql_real_connect(PMysql(@qmysql),nil,User,Password,nil,0,nil,0);
  // <... Prüfungen ...>
  Result := socket;
end;
//------------------------------------------------------------------------------
procedure dbAuswaehlen(socket: PMYSQL; datenbankname: PChar);
begin
  if mysql_select_db(socket,datenbankname) < 0 then ...
  // <... Programmabbruch ...>
end;
//------------------------------------------------------------------------------
procedure queryAusfuehren(socket: PMYSQL; Query: PChar);
begin
  if (mysql_query(socket,Query) < 0 then ...
  // <... Programmabbruch ...>
end;
//------------------------------------------------------------------------------
function queryResultBereitstellen(socket: PMYSQL): PMYSQL_RES;
var recordbuffer: PMYSQL_RES;
begin
  recordbuffer := mysql_store_result(socket);
  // <... Prüfungen ...>
  Result := recordbuffer;
end;
//------------------------------------------------------------------------------
procedure ergebnisdatensaetze_anzeigen(recordbuffer: PMYSQL_RES);
var rowbuffer: TMYSQL_ROW;
begin
  rowbuffer := mysql_fetch_row(recordbuffer);
  while (rowbuffer <>nil) do
  begin
    WriteLn('BuchId  : ', rowbuffer[ 2]);
    WriteLn('Bet_Euro: ', rowbuffer[ 5]);
    WriteLn('SH      : ', rowbuffer[ 7]);
    rowbuffer := mysql_fetch_row(recordbuffer);
  end;
  Writeln;
end;
//------------------------------------------------------------------------------
procedure aufraeumen(socket: PMYSQL; recordbuffer: PMYSQL_RES);
begin
  mysql_free_result(recordbuffer);
  mysql_close(socket);
end;
//------------------------------------------------------------------------------
end.
 

Bin für JEDE Hilfe dankbar !
Zuletzt geändert von manfred.mader@gmx.de am Mo 14. Sep 2015, 21:27, insgesamt 2-mal geändert.

Eb
Lazarusforum e. V.
Beiträge: 238
Registriert: Di 5. Feb 2008, 15:32
OS, Lazarus, FPC: Linux Mint - Laz 2.2.0
CPU-Target: 64Bit
Wohnort: Stuttgart

Re: MySQL: numerische Werte aus Tabelle lesen

Beitrag von Eb »

Es gibt bei MySQL eine CASE-Anweisung, welche im Select angewendet kann, z.B. so:

Code: Alles auswählen

SELECT nummer, erledigt 
,CASE
        WHEN erledigt = 'J' THEN -1 * nummer
        WHEN erledigt = 'N' THEN 1 * nummer
        ELSE 328
    END AS berechnet
FROM tabelle;

Gruß Eb

manfred.mader@gmx.de
Beiträge: 10
Registriert: Mo 6. Jul 2015, 09:09
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: 64Bit

Re: MySQL: numerische Werte aus Tabelle lesen

Beitrag von manfred.mader@gmx.de »

@eb:
Herzlichen Dank für den Hinweis! Dieses Case-Statement war mir unbekannt - ich hab's gleich ausprobiert und es tut auf Anhieb! Das Problem, in der Anzeige aus dem Soll-Haben-Kennzeichen ein Vorzeichen zu machen ist also dank deiner Hilfe gelöst.
Leider löst es aber nicht das grundsätzliche Problem: Der Verkehr zwischen Pascal-Programm und MySQL-Server läuft vollständig über (Ansi-)Strings: Die Query vom Prog an den Server ist einer, und auch die zurückgelieferte Ergebnismenge ist ein (i.W. array of) AnsiString. Da ich diejenigen Inhalte, die ihrer Natur nach (und ja auch in der Tabelle) numerisch sind, auch noch in anderer Weise zum "Rechnen" brauche, muß ich sie numerisch haben. (Wenn ich z.B. grafische Auswertungen machen will, brauche ich skalierte Koordinaten, die ich nur aus numerischen Werten gewinnen kann.) Kurzum, was ich brauche, ist eine Konvertierung der folgenden Art:

Code: Alles auswählen

var i: integer;
    s: string:
begin s:='17';
      i := [b]StrToInt[/b](s);
      writeln(i*i);
end;
 

Nur eben nicht für die Konvertierung String -> Integer, sondern für die Konvertierung AnsiString -> Float (oder Double oder sonstwas).
Trotzdem nochmal vielen Dank, das Case-Statement ist jetzt fest in meinen Hinterkopf geflashed.
Manfred
Zuletzt geändert von manfred.mader@gmx.de am Mo 14. Sep 2015, 21:29, insgesamt 3-mal geändert.

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: MySQL: numerische Werte aus Tabelle lesen

Beitrag von mse »

Was ist der Grund, dass du keine DB-Komponenten verwendest?
Die Plackerei direkt mit der DB-API zu arbeiten tun sich eigentlich nur Komponentenentwickler an.

manfred.mader@gmx.de
Beiträge: 10
Registriert: Mo 6. Jul 2015, 09:09
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: 64Bit

Re: MySQL: numerische Werte aus Tabelle lesen

Beitrag von manfred.mader@gmx.de »

mse hat geschrieben:Was ist der Grund, dass du keine DB-Komponenten verwendest?
Die Plackerei direkt mit der DB-API zu arbeiten tun sich eigentlich nur Komponentenentwickler an.


@mse: Dafür habe ich mehrere Gründe, und ich räume offen ein, dass keiner davon objektiv stichhaltig ist (deshalb betone ich das "ich" - jeder andere mag das mit Fug und Recht anders sehen).

1. Ich bin Lazarus/FPC-Newbie und kenne mich mit den DB-Komponenten schlicht (noch) nicht aus. Zwar habe ich schon professionell mit Pascal gearbeitet: Programmierung einer Scheibenwischermotoren-Prüfanlage für Bosch. Aber das war vor über 30 Jahren in einem Ingenieur-Büro, und wir verwendeten UCSD-Pascal und 6502-Assembler auf einem Apple ][. (Das war übrigens kein Bastelprojekt, auch wenn sich das heute so anhört - das Ding ist immerhin, inclusive aller Mechanik und Elektronik als Individualanfertigung für ca. 1 Mio DM über den Tisch gegangen.) Leider ging die Firma dann über den Bach - trotzdem ist Pascal seit damals meine "Muttersprache". Aber wenn man dann 30 Jahre lang so gut wie nicht mehr programmiert ... wird man zum Newbie.
Die i.F. noch angeführten Gründe gehen weitgehend auf diese Erfahrung zurück:

2. Eine gut funktionierende IDE ist fraglos eine tolle Sache (Code-Ergänzung, kontextsensitive Hilfe), die ich auch gern annehme. Was die Programme angeht, die ich selbst schreibe, bin ich aber eher konservativ: Ich will wissen, was in meinem Programm passiert, und warum, und ich will es selbst in der Hand haben (Kontrollzwang? :wink: ) Deswegen tue ich mich schwer mit irgendwelchen Komponenten, denen ich (übertrieben gesagt) nur mitteilen muß: "Da ist 'ne Datenbank und darin eine Tabelle. Mach mir mal eine tolle Tabelle daraus und gib mir gleich auch noch die grafische Auswertung dazu". Selbst wenn's funktioniert (was meist dann doch Stunden um Stunden an Experimenten erfordert, bist man's "hat"): wenn ich dann irgendwas etwas anders haben will als es der großartige Automatismus mir liefert, stelle ich plötzlich fest, daß ich vor einer verschlossenen BlackBox stehe, in die ich erst mal nicht reinkomme. (jaja, ich weiß, ich hab den Quelltext zur Verfügung ...) Also mach ich's lieber etwas umständlicher, aber eben selber ... !

3. Deswegen die von mir gewählte Design-Entscheidung:
- Aufbau einer Verbindung zum DB-Server
- Formulieren einer SQL-Query (die Parameter werden über eine mehr oder weniger hübsche GUI aufgenommen)
- Ausführen der Query
- Nimm aus der zurückgelieferten Ergebnismengen-Datenstruktur die Ergebnisse raus
- und verwende sie (als "normale, klassische" Pascal-Datentypen), um damit zu machen, was immer du vor hast.
Staight forward, konservativ, und meinetwegen auch langweilig ... aber (wenn's dabei unterwegs keine Stolpersteine gibt) funktioniert es, und zwar stabil!

4. Und last, but not least: Mein Stolperstein in dem hier in Rede stehenden Problem ist die Konvertierung gewisser Felder in der Ergebnismenge eines SQL-Selects ist deren Umwandlung von einem "komischen" Format in so was "Faßbares" und gut "Handlebares" wie ein Integer oder ein Double.
Und dazu fällt mir ein Satz aus einem Pascal-Buch Anfang der 90er-Jahre ein (in jenen Jahren wurde C als die eierlegende Wollmilchsau unter den Programmiersprachen gehandelt): "Lassen Sie sich niemals einreden, daß man in C irgendwelche Dinge machen kann, die in Pascal nicht gehen. Seien Sie versichert, daß alles, was C kann, Pascal auch kann!" (Nebenbei, ich hab mich auch mit C beschäftigt - aber richtig gemocht hab ich#s nie ...)
Das sagt mir: Ich weigere mich zu glauben, dass es unmöglich sein soll, einen AnsiString (oder auch einen Pointer darauf) in z.B. ein Double zu konvertieren, wenn der Inhalt sinnvoll so verwandelbar ist.

Sorry, mein Beitrag ist jetzt etwas länglich geworden, aber ich wollte den Einwurf von mse ehrlich und umfassend beantworten. Denn ich bin sicher, mse hat's wirklich gut gemeint, im Sinne von "Mensch, mach dir doch das Leben nicht unnötig schwer, da gibt's doch viel vorgefertigtes!" Warum ich mich trotzdem so entschieden hab - vielleicht konnte ich das hiermit verdeutlichen.

Beste Grüße in die Runde
Manfred

manfred.mader@gmx.de
Beiträge: 10
Registriert: Mo 6. Jul 2015, 09:09
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: 64Bit

Re: MySQL: numerische Werte aus Tabelle lesen

Beitrag von manfred.mader@gmx.de »

Könnte sein, dass ich einen Ansatz für das Problem gefunden habe: Datentyp Variant. Erste Versuche sahen schon sehr gut aus; ich werde den Weg mal weiter verfolgen und im Erfolgsfall detailliert darüber berichten. Gleichwohl: wenn jemand noch eine gute Idee hat - immer gern!
Gruß Manfred

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: MySQL: numerische Werte aus Tabelle lesen

Beitrag von Michl »

manfred.mader@gmx.de hat geschrieben:Kurzum, was ich brauche, ist eine Konvertierung der folgenden Art:

Code: Alles auswählen

var i: integer;
    s: string:
begin
  s := '17';
  i := [b]StrToInt[/b](s);
  writeln(i*i);
end;
 

Nur eben nicht für die Konvertierung String -> Integer, sondern für die Konvertierung AnsiString -> Float
Ist das noch eine Frage?

Wie es die Konvertierung für Integer gibt, gibt es sie auch für Floats:

Code: Alles auswählen

var
  d: Double;
  s: String:
begin
  s := '17.7'//oder 17,7 je nach DecimalSeparator
  d := StrToFloat(s);
  writeln(d * d);
end;


PS: Willkommen im Lazarusforum!

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: MySQL: numerische Werte aus Tabelle lesen

Beitrag von mse »

manfred.mader@gmx.de hat geschrieben:
mse hat geschrieben:Was ist der Grund, dass du keine DB-Komponenten verwendest?
Die Plackerei direkt mit der DB-API zu arbeiten tun sich eigentlich nur Komponentenentwickler an.


@mse: Dafür habe ich mehrere Gründe, und ich räume offen ein, dass keiner davon objektiv stichhaltig ist (deshalb betone ich das "ich" - jeder andere mag das mit Fug und Recht anders sehen).

Na dann viel Spass! Mache dich auf eine längere Sitzung gefasst. ;-)
Vielleicht kannst du dir einige Anregungen von hier holen:
https://gitlab.com/mseide-msegui/mseide ... qlconn.pas

Antworten