[gelöst] Lazarus und berechnete Firebird-Felder

Für Themen zu Datenbanken und Zugriff auf diese. Auch für Datenbankkomponenten.
Antworten
Joh
Lazarusforum e. V.
Beiträge: 288
Registriert: Sa 26. Mai 2012, 17:31
OS, Lazarus, FPC: Win 10 (L 2.2.6 x64 FPC 3.2.2)
CPU-Target: 64Bit

[gelöst] Lazarus und berechnete Firebird-Felder

Beitrag von Joh »

Mein nächstes Firebird-Drama:

Ich möchte ein wenig Berechnungen in die Datenbank auslagern, damit mir z.B. nicht wieder ein Lazarus-Rundungsfehler mit Currency-Werten auftritt:

Eine View mit

Code: Alles auswählen

CREATE VIEW test (id, menge, ekpreis, Summe) AS SELECT id, Menge, ekpreis, ROUND(Menge*ekPreis,2) AS SUMME FROM Rechnungpos
erstellt.
Dann die Abfrage

Code: Alles auswählen

SELECT id, Menge, ekpreis, Summe FROM test

Überall werden die Daten sauber angezeigt; nur in Lazarus kommen die Daten des berechneten Feldes aus der VIEW nicht an...
Hier wird einfach nichts ausgegeben:
SQL1.png
SQL1.png (8.11 KiB) 1518 mal betrachtet
Die Felder werden gefunden

SQL2.png
SQL2.png (15.37 KiB) 1518 mal betrachtet
Der SQL-Befehl wird angenommen

SQL3.png
SQL3.png (15.02 KiB) 1518 mal betrachtet
und ausgeführt, aber ohne Daten.
Das zieht sich latürnich bis zum Formular durch.
Warum?

edit: AS SUMME eingefügt
Zuletzt geändert von Joh am Fr 6. Jun 2025, 15:23, insgesamt 2-mal geändert.
just my two Beer

Soner
Beiträge: 734
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: Lazarus und berechnete Firebird-Felder

Beitrag von Soner »

Sowie ich das sehe, hast du kleiner Flüchtigkeitsfehler, passiert mir auch.
Das ist dein View:
CREATE VIEW test (id, menge, ekpreis, Summe) AS SELECT id, Menge, ekpreis, ROUND(Menge*ekPreis,2) FROM Rechnungpos
Das ist dein Abfrage:
SELECT id, Menge, ekpreis, Summe FROM test.

Die Spalte Summe ist nicht definiert. Vielleicht solltest du das ergänzen:
.. ROUND(Menge*ekPreis,2) AS Summe ...

Solange man berechnetes Feld mit "AS ..." keinen Namen angibt, hat es komischen Namen, in deinem Fall wahrscheinlich ROUND.

Edit: Noch etws, Verwende auf Windows und 64Bit-FPC niemals Currency, Rechne immer in Double und Runde auf 4 Stellen für Zwischenergebnisse. Wenn du in Funktionsparameter irgendwo Currency oder ähnliches siehst oder sicher gehen möchtest, mach explizite Typumwanlung wie:
funktionxy(double(x*b/2));

Joh
Lazarusforum e. V.
Beiträge: 288
Registriert: Sa 26. Mai 2012, 17:31
OS, Lazarus, FPC: Win 10 (L 2.2.6 x64 FPC 3.2.2)
CPU-Target: 64Bit

Re: Lazarus und berechnete Firebird-Felder

Beitrag von Joh »

UUPS... entschuldige.

Ich hatte das ganze nachträglich fürs Forum angepaßt. Im Original war ein "AS SUMME" drin.
Ich hab es oben auch korrigiert.
just my two Beer

Benutzeravatar
Zvoni
Beiträge: 396
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz 2.2.2 FPC 3.2.2)
CPU-Target: 32Bit
Wohnort: BW

Re: Lazarus und berechnete Firebird-Felder

Beitrag von Zvoni »

Wieso benutzt du nicht eine computed column?
https://www.firebirdsql.org/file/docume ... -ddl-table
https://stackoverflow.com/questions/641 ... erver-side

IMO, der Vorteil ist, dass deine berechnete Spalte einen "echten" Datentyp bekommt, und du ggfs. nicht durch die Botanik herum casten musst

Code: Alles auswählen

CREATE [GLOBAL TEMPORARY] TABLE tablename
  [EXTERNAL [FILE] 'filespec']
  (<col_def> [, {<col_def> | <tconstraint>} ...])
  [{<table_attrs> | <gtt_table_attrs>}]

<col_def> ::=
    <regular_col_def>
  | <computed_col_def>
  | <identity_col_def>

<regular_col_def> ::=
  colname {<datatype> | domainname}
  [DEFAULT {<literal> | NULL | <context_var>}]
  [<col_constraint> ...]
  [COLLATE collation_name]
  
-- HIER!!!
<computed_col_def> ::=
  colname [{<datatype> | domainname}]
  {COMPUTED [BY] | GENERATED ALWAYS AS} (<expression>)
also in der Art

Code: Alles auswählen

CREATE TABLE RechnungsPos
  (ID INT, Menge INT, ekpreis DOUBLE, Summe DOUBLE GENERATED ALWAYS AS (Menge*ekpreis)
  );
Und das "Round" brauchste erst beim abholen (SELECT).
Da es sich hier um "Geld" handelt, möchte ich an den "Trick" erinnern, für ekpreis ggfs. Integer zu verwenden, und beim Speichern/Abholen einfach das Komma zu verschieben.
Also im Sinne von: ekpreis ist dann in "EURO-Cent" (Nicht EURO)
Bsp. ekpreis = 1234 --> "1234 €-Cent" ("12,34 €")
Bei der Berechnung (Summe) wäre das einfach eine Multiplikation von zwei Integers, und zur Anzeige (Im SELECT) dann einfach geteilt durch 100.
Kein Runden notwendig
Oder das geteilt durch 100 gleich in die computed Column

Code: Alles auswählen

CREATE TABLE RechnungsPos
  (ID INT, Menge INT, ekpreis INT, Summe DOUBLE GENERATED ALWAYS AS (Menge*ekpreis/100.0)
  );
Nachtrag: Das Runden brauchst du nur, falls "Menge" keine Integers wären (Bsp. "7,5 Meter")
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.

Joh
Lazarusforum e. V.
Beiträge: 288
Registriert: Sa 26. Mai 2012, 17:31
OS, Lazarus, FPC: Win 10 (L 2.2.6 x64 FPC 3.2.2)
CPU-Target: 64Bit

Re: Lazarus und berechnete Firebird-Felder

Beitrag von Joh »

Zvoni hat geschrieben: Fr 6. Jun 2025, 08:03 Wieso benutzt du nicht eine computed column?
Das mit den berechneten Spalten kingt ganz gut.
Zumindest in den Fällen, wo ich die Daten häufiger und regelmäßig abrufe. Für eine einmalige Statistik eher overkill.

Aber dein Nebensatz mit dem "in der Botanik rumcasten" hat mich auf die Spur gebracht:

Wenn ich direkt in der View, also in der Datenbank caste:

Code: Alles auswählen

CREATE OR ALTER VIEW TEST (ID, MENGE, EKPREIS, SUMME)
AS
SELECT id, Menge, ekpreis, CAST(Round(Menge*ekPreis,2) AS DECIMAL(10,2)) AS Summe 
FROM Rechnungpos;
meckert Lazarus nicht rum; ich habe die Statistikdaten in die Datenbank ausgelagert und kann sauber von Lazarus mit

Code: Alles auswählen

SELECT id, Menge, ekpreis, Summe FROM test
drauf zugreifen.

Ich verstehe zwar immer noch nicht, was Lazarus an dem generiertem Datentyp (Decimal(38,5)) zu meckern hat,
aber ist eigentlich auch egal,
bevor ich mich hier völlig echauffiere
...


Integers als Beträge war mir noch nie geheuer und ist auch keine Option, solange ich nicht alleiger Herr über die Daten bin.
just my two Beer

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6845
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Lazarus und berechnete Firebird-Felder

Beitrag von af0815 »

Joh hat geschrieben: Fr 6. Jun 2025, 15:22 Ich verstehe zwar immer noch nicht, was Lazarus an dem generiertem Datentyp (Decimal(38,5)) zu meckern hat,
aber ist eigentlich auch egal,
bevor ich mich hier völlig echauffiere
...


Integers als Beträge war mir noch nie geheuer und ist auch keine Option, solange ich nicht alleiger Herr über die Daten bin.
Dazu muss man sich in der SQLdb oder ZEOS ansehen, wie die SQL-Datentypen auf die FPC-Datentypen gemappt werden. Dazu braucht natürlich auch klare Informationen, was das für ein Datentyp ist. Und das ist aus Sicht der SQLdb manchmal nicht so klar. Einen Decimal(38,5) wirst du in FPC/Lazarus so nicht finden. Daher wird mal geraten, welcher Typ vielleicht Ähnlichkeiten hat.

Siehe ua. LoadField in SQLite3Conn.pp in den Sourcen vom FPC. Dort ist aber der Typ schon bekannt, trotzdem sieht man hier wie gemappt wird. Und das ist für jede Connection (daher ander Datenbank) anders.

Ja SQL Datenbanken sind eine eigene Welt mit eigenen Datentypen und die Programmiersprachen haben eigene Datentypen die meistens an die CPU angelehnt sind. Das kann oft nur mit Verlusten bzw. Ungenauigkeiten übersetzt werden. Dessen muss man sich bewusst sein und damit rechnen.


Integer als Beträge sind gar nicht so ungewöhnlich. Der Datentyp Currency macht von sowas genaugenommen gebrauch. Wenn zum Beispiel festgelegt ist, das Berechnungen immer mit 4 Nachkommastellen ohne Rundung bearbeitet werden, ist ein Ganzahltyp die beste Wahl und man verschiebt einfach das Komma um 4 Stellen. Damit wird immer korrekt gerechnet.
Bei Single, Bouble, Float etc. hat man immer das Problem, das sicht nicht immer alle Zahlen korrekt abbilden lassen, aber das haben wir hier im Forum mehr als einmal bereits durchgekaut. Deswegen kann Integer bzw. größere ganzahlige Typen eine gute Option sein.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Joh
Lazarusforum e. V.
Beiträge: 288
Registriert: Sa 26. Mai 2012, 17:31
OS, Lazarus, FPC: Win 10 (L 2.2.6 x64 FPC 3.2.2)
CPU-Target: 64Bit

Re: [gelöst] Lazarus und berechnete Firebird-Felder

Beitrag von Joh »

af0815 hat geschrieben: Fr 6. Jun 2025, 16:09 Dazu muss man sich in der SQLdb oder ZEOS ansehen, wie die SQL-Datentypen auf die FPC-Datentypen gemappt werden. Dazu braucht natürlich auch klare Informationen, was das für ein Datentyp ist. Und das ist aus Sicht der SQLdb manchmal nicht so klar. Einen Decimal(38,5) wirst du in FPC/Lazarus so nicht finden. Daher wird mal geraten, welcher Typ vielleicht Ähnlichkeiten hat.
Ist übrigens SQLdb, das hatte ich nicht erwähnt.
ich hatte ja gedacht, das size und Precision bei den Feldern genau das einstellen können.
Zusammen mit dem Feldtyp: TBCDField.

warum eigentlich TBCDField bei decimal und nicht TNumericField? Naja, erstmal egal.

af0815 hat geschrieben: Fr 6. Jun 2025, 16:09 Integer als Beträge sind gar nicht so ungewöhnlich. Der Datentyp Currency macht von sowas genaugenommen gebrauch. Wenn zum Beispiel festgelegt ist, das Berechnungen immer mit 4 Nachkommastellen ohne Rundung bearbeitet werden, ist ein Ganzahltyp die beste Wahl und man verschiebt einfach das Komma um 4 Stellen. Damit wird immer korrekt gerechnet.
Kann man machen, aber damit würde ich andere Strukturen beeinflussen.

af0815 hat geschrieben: Fr 6. Jun 2025, 16:09 Bei Single, Bouble, Float etc. hat man immer das Problem, das sicht nicht immer alle Zahlen korrekt abbilden lassen, aber das haben wir hier im Forum mehr als einmal bereits durchgekaut. Deswegen kann Integer bzw. größere ganzahlige Typen eine gute Option sein.
Real-Typen sind noch nie für soetwas gut gewesen.
Deshalb würde ich auch decimal bevorzugen.
just my two Beer

Benutzeravatar
Zvoni
Beiträge: 396
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz 2.2.2 FPC 3.2.2)
CPU-Target: 32Bit
Wohnort: BW

Re: [gelöst] Lazarus und berechnete Firebird-Felder

Beitrag von Zvoni »

Joh hat geschrieben: Fr 6. Jun 2025, 21:14
af0815 hat geschrieben: Fr 6. Jun 2025, 16:09 Integer als Beträge sind gar nicht so ungewöhnlich. Der Datentyp Currency macht von sowas genaugenommen gebrauch. Wenn zum Beispiel festgelegt ist, das Berechnungen immer mit 4 Nachkommastellen ohne Rundung bearbeitet werden, ist ein Ganzahltyp die beste Wahl und man verschiebt einfach das Komma um 4 Stellen. Damit wird immer korrekt gerechnet.
Kann man machen, aber damit würde ich andere Strukturen beeinflussen.
Und wenn man dann sieht wie FireBird das intern macht, kann man nen Kalauer-Witz daraus ableiten :lol: :lol: :lol:
https://firebirdsql.org/file/documentat ... types.html
Storage ExamplesThe storage format in the database for DECIMAL is very similar to NUMERIC, with some differences that are easier to observe with the help of some more examples:

DECIMAL(4) stored as INTEGER (exact data)
DECIMAL(4,2) INTEGER (data * 10^2) <-- DAS HIER !!
DECIMAL(10,4) (Dialect 1) DOUBLE PRECISION
(Dialect 3) BIGINT (data * 10^4)
EDIT: und hab erst jetzt den hier gesehen:
Ich verstehe zwar immer noch nicht, was Lazarus an dem generiertem Datentyp (Decimal(38,5)) zu meckern hat,
Eine fixe Gleitkommazahl mit insgesamt 38 Ziffern, davon maximal 5 Nachkommastellen?
38 Ziffern????
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.

Antworten