fkCalculated Feld - SQLITE3 Datenbank - Änderungen gehen verloren...

Für Themen zu Datenbanken und Zugriff auf diese. Auch für Datenbankkomponenten.
Meridian
Beiträge: 42
Registriert: Di 22. Feb 2022, 12:19
OS, Lazarus, FPC: Window 11
CPU-Target: 64Bit
Wohnort: Cloppenburg

Re: fkCalculated Feld - SQLITE3 Datenbank - Änderungen gehen verloren...

Beitrag von Meridian »

charlytango hat geschrieben: Sa 12. Apr 2025, 09:57 Warum zum Geier wettere ich ewiglich gegen 'SELECT *' ??

Das ist nicht nur schlechter Stil sondern bringt heftig Probleme.
Im Ablauf, im Code, in der Performance etc.
Und weil wir gerade dabei sind, eine SQL Anbindung ohne Möglichkeit zum Monitoring (also was kommt vom Server und was wird hin geschickt) ist Murks zum Programmieren.

Wie wärs denn, wenn du ein sauberes SELECT in tbLagerB verwendest?
Das alleine würde das Update-Problem schon lösen. Probier es aus.

Und wenn du es besonders schön machen willst, dann setze den Updatemode auf upWhereKeyOnly und trag ein sauberes Update Statement ein, wie es wp_xyz vorgeschlagen hat

Und weil Ostern kommt gibts auch Geschenke

Code: Alles auswählen

    tbLagerB.SQL.Text := 'SELECT ID,Artikel_Nr,Hersteller_Nr,Hersteller,Bezeichnung,Warengruppe,Bestand,Lagerort,E_Preis FROM LAGERVERWALTUNG';


    tbLagerB.UpdateSQL.Text:= 'UPDATE LAGERVERWALTUNG '+
                              'SET ' +
                              'Artikel_Nr = :Artikel_Nr, Hersteller_Nr = :Hersteller_Nr, Hersteller = :Hersteller, Bezeichnung = :Bezeichnung, '+
                              'Warengruppe = :Warengruppe, Bestand = :Bestand, Lagerort = :Lagerort, E_Preis = :E_Preis '+
                              'WHERE ID = :ID';
Vielen Dank für die Tipps und das Ostergeschenk. Ich habe es umsetzen können, es klappt.

Meridian
Beiträge: 42
Registriert: Di 22. Feb 2022, 12:19
OS, Lazarus, FPC: Window 11
CPU-Target: 64Bit
Wohnort: Cloppenburg

Re: fkCalculated Feld - SQLITE3 Datenbank - Änderungen gehen verloren...

Beitrag von Meridian »

Zvoni hat geschrieben: Mo 14. Apr 2025, 08:19
Maddias hat geschrieben: So 13. Apr 2025, 07:15
Meridian hat geschrieben: Mi 9. Apr 2025, 16:15 Habe festgestell, dass bei Verwendung eines Datenbank-Feldes als fkCalculated (und nur dann) die Änderungen (in allen anderen Feldern) nach einem Refresh nicht übernommen werden.
Hallo Meridian,

ein berechnetes Feld braucht keine Spalte in der Datenbank-Tablle! Du kannst die Spalte G_Preis löschen in beiden SQLite DBs. Sie ist überflüssig, weil die Daten zur Berechnung schon in der Datenbank gespeichert sind (Bestand & E_Preis),

Auch würde ich die Spaltenbreite in der statischen Feldliste setzen als DisplayWidth. Dort ist sie aber nicht in Pixel sondern in Anzahl Buchstaben angegeben.

Salut,
Mathias
Muss ich widersprechen.
Wieso etwas im Frontend machen, wenn es die Datenbank selbst kann (und meist besser)?

Tabellenerstellung ändern:

Code: Alles auswählen

s := 'CREATE TABLE LAGERVERWALTUNG(';
  s := s + ' ID INTEGER PRIMARY KEY AUTOINCREMENT,';
  s := s + ' Artikel_Nr VARCHAR(15),';  //Hier fehlt NON NULL und UNIQUE --> Eine Artikel_Nr darf nicht leer sein, und muss eimalig sein
  s := s + ' Hersteller_Nr VARCHAR(15),';
  s := s + ' Hersteller VARCHAR(20),';
  s := s + ' Bezeichnung VARCHAR(40),';  //Hier NON NULL, ggfs. sogar noch dazu UNIQUE
  s := s + ' Warengruppe VARCHAR(30),';
  s := s + ' Bestand Integer,';  //DEFAULT 0
  s := s + ' Lagerort VARCHAR(15),';
  s := s + ' E_Preis REAL,';
  s := s + ' G_Preis REAL GENERATED ALWAYS AS (Bestand*E_Preis) STORED';  //HIER!!!
  s := s + ');';
Anstatt STORED kann man auch VIRTUAL nehmen.
Unterschied: STORED wird das Feld bei einem INSERT/UPDATE beschrieben, und braucht auch physisch Platz in der Datenbank/Platte.
VIRTUAL wird immer bei einem SELECT neu berechnet. --> ist vom Prinzip her dasselbe wie ein "SELECT ..... (Bestand*E_Preis) As G_Preis FROM....."
Der Unterschied ist, dass du bei einer GENERATED COLUMN einen expliziten Datentyp angeben kannst.
Was man wann nimmt musst du selbst wissen.
Hast du 1 Million Datensätze, ist STORED besser, weil nur "einmal" berechnet wird (Beim INSERT/UPDATE)
Hast du 1 Million Datensätze und machst nen SELECT ohne LIMIT wird bei VIRTUAL auch 1 Million mal neu gerechnet.
Grundsätzlich: "G_Preis" verhält sich wie eine reguläre Spalte einer Tabelle, aber eben , dass du nichts machen musst um sie zu "berechnen"

NotaBene: Du wirst NIEMALS ein INSERT/UPDATE auf die Spalte "G_Preis" selbst machen.
"G_Preis" (bei STORED) wird IMMER neu berechnet, wenn du einen INSERT/UPDATE auf die Tabelle machst.
Also ein "INSERT INTO Tabelle1(Spalten OHNE G_preis) VALUES(....)" wird IMMER die Spalte "G_Preis" neu berechnen
Ein "UPDATE Tabelle1 SET Bestand=2000 WHERE ID=42" wird IMMER die Spalte "G_Preis" neu berechnen

Weiter im Text: Ich würde mir mal Gedanken darüber machen, welche Spalten NON NULL und/oder UNIQUE sein sollen (Artikel_Nr und/oder Bezeichnung springt mir sofort ins Auge).
Desweiteren: Bestand sollte einen DEFAULT-Wert von 0 bekommen, ansonsten bekommst du Datenbank-NULLs.

Warum hacke ich darauf rum? Ja, du wirst wahrscheinlich argumentieren "Das mache ich alles aus meinem Frontend"
"Ja, und? Ich nehm dann DB-Browser for SQLite, öffne die Datenbanken ausserhalb deiner Lazarus-App, und zerlege das ganze Ding"

Ändere die Datenbank wie oben ab, wirf die zwei OnCalcFields-Prozeduren in die Tonne, und Feuer frei.
Mit obiger Struktur bist du noch immer in deinem Design, und musst nicht viel ändern.

Oh, und was Charly gesagt hat: SELECT * FROM ist ne tickende Zeitbombe

Und das AUTOINCREMENT brauchst auch nicht. In die Tonne damit. Ist bei SQLite nur unnötiger Overhead.
Auch dir ein dickes Dankeschön. Habe viel gelernt und einiges sehr viel besser verstanden.

Meridian
Beiträge: 42
Registriert: Di 22. Feb 2022, 12:19
OS, Lazarus, FPC: Window 11
CPU-Target: 64Bit
Wohnort: Cloppenburg

Re: fkCalculated Feld - SQLITE3 Datenbank - Änderungen gehen verloren...

Beitrag von Meridian »

Ich habe das von Zvoni umgesetz...

Code: Alles auswählen

s := 'CREATE TABLE LAGERVERWALTUNG(';
  s := s + ' ID INTEGER PRIMARY KEY AUTOINCREMENT,';
  s := s + ' Artikel_Nr VARCHAR(15),';  //Hier fehlt NON NULL und UNIQUE --> Eine Artikel_Nr darf nicht leer sein, und muss eimalig sein
  s := s + ' Hersteller_Nr VARCHAR(15),';
  s := s + ' Hersteller VARCHAR(20),';
  s := s + ' Bezeichnung VARCHAR(40),';  //Hier NON NULL, ggfs. sogar noch dazu UNIQUE
  s := s + ' Warengruppe VARCHAR(30),';
  s := s + ' Bestand Integer,';  //DEFAULT 0
  s := s + ' Lagerort VARCHAR(15),';
  s := s + ' E_Preis REAL,';
  s := s + ' G_Preis REAL GENERATED ALWAYS AS (Bestand*E_Preis) STORED';  //HIER!!!
  s := s + ');';
Bei Verwendung von GENERATED ALWAYS AS ...

Code: Alles auswählen

s := s + ' G_Preis REAL GENERATED ALWAYS AS (Bestand*E_Preis) STORED';
kommt nach einem Post eine Fehlermeldung. Siehe Anhang.
Dateianhänge
Screenshot Fehlermeldung.png
Screenshot Fehlermeldung.png (11.74 KiB) 1526 mal betrachtet

Benutzeravatar
Zvoni
Beiträge: 363
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: fkCalculated Feld - SQLITE3 Datenbank - Änderungen gehen verloren...

Beitrag von Zvoni »

Ich versteh das Problem nicht.....

Siehe Anhang. Proof of Concept.
und schaut mal GENAU in SQL, InsertSQL und UpdateSQL vom TSQLQuery rein.
So wie es wp_xyz auch bereits erwähnt hat!
benötigt sqlite3.dll im Projekt-Ordner.
SQLite-DB ist InMemory

Geht auf das DBGrid, fügt Sätze hinzu (DeleteSQL habe ich nicht getestet), ändert Sätze (Bestand oder Preis), und ihr werdet sehen, wie G_Preis autmagisch neu gerechnet wird
Spalte G_Preis sollte eigentlich auf ReadOnly gesetzt werden (war ich jetzt zu faul)
SQLiteStored.zip
(139.98 KiB) 30-mal heruntergeladen
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.

Meridian
Beiträge: 42
Registriert: Di 22. Feb 2022, 12:19
OS, Lazarus, FPC: Window 11
CPU-Target: 64Bit
Wohnort: Cloppenburg

Re: fkCalculated Feld - SQLITE3 Datenbank - Änderungen gehen verloren... (gelöst)

Beitrag von Meridian »

Vielen Dank für umfangreiche Unterstützung

Antworten