Allgemeines zum Umgang mit Datenbanken

Für Themen zu Datenbanken und Zugriff auf diese. Auch für Datenbankkomponenten.
ErnstVolker
Beiträge: 327
Registriert: Di 17. Feb 2009, 10:44
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: Allgemeines zum Umgang mit Datenbanken

Beitrag von ErnstVolker »

Guten Tag Zusammen,

vielen Dank für Eure Tipp's. Hätte gar nicht gedacht dass es so viele und umfangreiche Antworten gibt. Ich bin in einigen Programmierforen angemeldet (mehr oder weniger -aktuell eher weniger aktiv) aber hier gibt es IMMER sehr zeitnahe, freundliche und hilfreiche Antworten. Großes Lob und vielen Dank!!

Eine Antwort kann ich mir sogar selber geben:
Dann noch zu einem Problem beim Mac. Zur Laufzeit werden die DLL hier dylib von Firebird nicht gefunden oder es gibt keinen Zugriff. Wäherend des Designs schon. Das hab' ich entsprechend hinbekommen einzustellen bzw. mit dem LibraryLoader die notwendige *.dylib geladen.
Wenn man den LibraryLoader auf das Startformular legt, welches beim Programmstart zuerst geladen wird, dann funktioniert es auch. Ich hatte ihn auf das Formular, welches das Übersichts-Grid der Hauptdateneingabe enthält, gelegt. Das wird aber erst später aufgerufen. Deshalb ging es wohl nicht.

Viele Grüße
Volker

ErnstVolker
Beiträge: 327
Registriert: Di 17. Feb 2009, 10:44
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: Allgemeines zum Umgang mit Datenbanken

Beitrag von ErnstVolker »

Guten Tag,

ich habe bei der Suche nach meinem Problem etwas von mir hier gefunden, wo ich mal weiter Frage:

Ich habe mehrere Tabellen. Eine ist die Haupttabelle des Projektes, einige Nebentabellen ("Zweispalter": Nur PK und Inhalt) und Koppeltabellen (für m:n-Verknüpfungen).
Bei einem Insert in die Haupttabelle wird durch die DB (Postgres) automatisch der PK als uuid erzeugt. Dieser ist in der Koppeltabelle einer der FK's.

Wie bekomme ich es von Lazarus aus hin, dass beim Insert in die Haupttabelle auch ein Insert in der Koppeltabelle erfolgt und dabei der PK aus der Haupttabelle (die automatisch erzeugte uuid) übernommen wird?

Ich habe folgenden Ansatz probiert:

Code: Alles auswählen

Params.CreateParam(ftGuid,'uuid',ptInput);
Params.ParamByName('uuid').AsGuid:= und hier die query der Haupttabelle von wo die uuid kommen soll
Das funktioniert aber nicht, weil es keine Übernahme/Übergabe "AsGuid" gibt.
Der Versuch einen uuid-Parameter als String zu definieren ging auch in die Hose.

Wie definiert und übergibt man einen uuid-Parameter?

Ich wünsche Euch ein paar besinnliche Feiertage und ein schönes Osterfest!
Viele Grüße
Volker

Benutzeravatar
gladio
Beiträge: 217
Registriert: Sa 21. Jun 2014, 06:15
OS, Lazarus, FPC: Win10-64 - aktuelle Lazarus/FPC Standard-Edition
CPU-Target: 64Bit
Wohnort: Rügen

Re: Allgemeines zum Umgang mit Datenbanken

Beitrag von gladio »

Du kannst das Ereignis AfterInsert der Query1 entsprechend auslösen, dass in die andere Tabelle ein neuer Datensatz mit den Gewünschten Werten eingefügt wird.
Die Ereignisse für die Querys findest du im zweiten Reiter des Objektinspektors.

charlytango
Beiträge: 843
Registriert: Sa 12. Sep 2015, 12:10
OS, Lazarus, FPC: Laz stable (2.2.6, 3.x)
CPU-Target: Win 32/64, Linux64
Wohnort: Wien

Re: Allgemeines zum Umgang mit Datenbanken

Beitrag von charlytango »

Das Problem mit der Weitergabe von Primary Keys ist ein ganz altes.

Grundlegend kann man das auf zwei Arten lösen:

1.) man kümmert sich selbst um das Erstellen von Primary Keys (da gibt es einige Möglichkeiten die ich aber nicht mehr empfehlen würde)

2.) Man überlässt das der DB, denn mittlerweile lösen das aktuelle SQL-Datenbanken verlässlich auch im Mehrbenutzermodus.

Und da gibt es je nach verwendeter DB auch unterschiedliche Ansätze. Auch philosophische Überlegungen oder solche nach Performance spielen oft eine Rolle wie viel man in der DB machen möchte (zB über Insert- oder Update-Trigger) oder ob der Client zuständig ist.

Ich persönlich erledige solche Dinge gerne im Client um unabhängig von individuellen DB-Eigenheiten zu sein.
Anders gesagt, nach einem Insert erfrage ich den soeben neu in die DB eingetragenen PK und verwende ihn für andere refernzielle Einträge in anderen Tabellen weiter.
Trigger werden dann nur zum Optimieren besonderer Abfragetabellen benötigt die nicht über Views erledigt werden können.

Jede DB hat übrigens ihre eigen Syntax zur Abfrage des letzten aktuellen PK.
Um da nicht durcheinander zu kommen mache ich so eine Abfrage immer sofort und unmittelbar nach dem Insert. Just to be sure.


Syntax für Postgres habe ich hier und hier gefunden.

Offensichtlich gibt es bei Postgres (bin da kein Spezialist dafür) mehrere Varianten in Abhängigkeit der Art des autoincrement das benutzt wird.

In stackoverflow werden alle Varianten gut erklärt denk ich

ErnstVolker
Beiträge: 327
Registriert: Di 17. Feb 2009, 10:44
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: Allgemeines zum Umgang mit Datenbanken

Beitrag von ErnstVolker »

Vielen Dank für die Hinweise.

Das mit der AfterInsert-Prozedur krieg ich noch nicht an's laufen.
Man schreibt dochdas hier:

Code: Alles auswählen

Query1.FieldByName('name_uuid').AsVariant:= DataSet.FieldByName('name_uuid').AsVariant
in die Prozedur.

Ich bekomme den Wert nicht rüber.

Morgen werde ich Das mit RETURN des PK aus Postgres heraus probieren.

Gute Nacht!

charlytango
Beiträge: 843
Registriert: Sa 12. Sep 2015, 12:10
OS, Lazarus, FPC: Laz stable (2.2.6, 3.x)
CPU-Target: Win 32/64, Linux64
Wohnort: Wien

Re: Allgemeines zum Umgang mit Datenbanken

Beitrag von charlytango »

ich würde der Versuchung widerstehen ein Insert-Statement zu verwenden das auch Werte zurück gibt.

..also etwas in der Art wie:

INSERT INTO tbl_TestReturnID (Name,Address)
VALUES ('Anvesh','Hyderabad') RETURNING Rno;


Ich kenne die Implementierung der SQL_Zugriffskomponente nicht so genau (egal ob SQLDB oder ZEOS)

Wenn du die Inserts ganz normal mit den Komponenten machst und nach

Code: Alles auswählen

  SQLQuery1.Post;
  SQLQuery1.ApplyUpdates;
sofort den neuen PK abfragst sollte das in jedem Fall klappen.

nur kurz skizziert als Pseudocode ohne test:

Code: Alles auswählen


integervariable:=RunSqlGetLastID;

function TSQLConnectParent.RunSqlGetLastID: integer;
var
  MyQry:TSQLQuery;
begin
  MyQry:=TSQLQuery.Create;
  try
     MyQry.Connection := DB-Verbindung zuweisen: SQLDB Connection oder ZEOS Connection;
     MyQry.SQL.Text:= 'select lastval(' +quotedstr('tablename')+');';
     MyQry.Open;
     MyQry.FindFirst;
     result := MyQry.Fields[0].AsInteger;
  finally
    freeandnil(MyQry);
  end;

end; 

Benutzeravatar
gladio
Beiträge: 217
Registriert: Sa 21. Jun 2014, 06:15
OS, Lazarus, FPC: Win10-64 - aktuelle Lazarus/FPC Standard-Edition
CPU-Target: 64Bit
Wohnort: Rügen

Re: Allgemeines zum Umgang mit Datenbanken

Beitrag von gladio »

Das wird so nichts
Query1.FieldByName('name_uuid').AsVariant:= DataSet.FieldByName('name_uuid').AsVariant
Das Prinzip wäre (ohne SQL zu bemühen)

Code: Alles auswählen

Query1.AfterInsert;
if Query2.Active= falte then 
Query2.open;
Query2.insert;
Query2Feldname1.AsXXX := Query1Feldname.AsXXX;
Query2Feldname2.AsXXX := ....
Query2.Post;
Query2.close;
Wurde weiter oben schon empfohlen: Pro Datentabelle eine Query, pro Datenbank eine Connection
und er Zugriff entweder über die Query's ODER über die jeweiligen Dataset's.
Strikt und geradeaus durch die Manteltasche

ErnstVolker
Beiträge: 327
Registriert: Di 17. Feb 2009, 10:44
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: Allgemeines zum Umgang mit Datenbanken

Beitrag von ErnstVolker »

Guten Morgen,

Genau das ist es:

Code: Alles auswählen

Query2Feldname1.AsXXX := Query1Feldname.AsXXX;
Das "AsXXX"! Wie wird eine uuid gehandhabt?

Was nimmt man für AsXXX bei einer uuid?

Vielen Dank

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6199
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: Allgemeines zum Umgang mit Datenbanken

Beitrag von af0815 »

wenn man einen uuid verwendet ist die Sache einfacher. Den UUID von Lazarus erzeugen lassen und verwenden, da braucht man nichts mehr abfragen. Ansonsten, wenn die DB einen Generator anbietet den verwenden und ebfalls alles easy buchen.
Bei manchen DBs heissen die Generatoren auch Sequenz(er).
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

ErnstVolker
Beiträge: 327
Registriert: Di 17. Feb 2009, 10:44
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: Allgemeines zum Umgang mit Datenbanken

Beitrag von ErnstVolker »

Ich stehe auf dem Schlauch!

Postgres erzeugt mit: "gen_random_uuid()" die uuid. Die sieht so aus: "f853fff3-09df-47b6-835f-65ef7ffcbdc7"

Wie "buche ich easy"? Die uuid muß doch irgendwie nach Lazarus kommen?

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6199
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: Allgemeines zum Umgang mit Datenbanken

Beitrag von af0815 »

Schon mal nach Lazarus und GUID oder UUID gesucht

https://www.freepascal.org/docs-html/rt ... eguid.html

Ist ein eigener Typ TGUID und kann mit GUIDToString und StringToGUID zwischen String und GUID gewandelt werden.

In deinem Fall kannst du ja die Guid aus prostgres auslesen (bei postgre kenn ich die Syntax nicht, beim MS-SQl würde ich das über eine Funktion erledigen) und dann alle Buchungen mit der GUID in Lazarus durchführen. Das mit Lazarus die Guid zu erzeugen ist universell, weil es auf allen Plattformen eine GUID liefert unabhängig davon ob die DB das liefern kann.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

ErnstVolker
Beiträge: 327
Registriert: Di 17. Feb 2009, 10:44
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: Allgemeines zum Umgang mit Datenbanken

Beitrag von ErnstVolker »

Ja, ich habe nach nach Lazarus und TGUID gesucht und gefunden.

Auslesen kann ich das uuid-Feld der Tabelle als String. Dummerweise habe ich in der Tabelle wo die uuid wieder hinein soll auch den Datentyp uuid verwendet. Klar kann mit StringToGUID wieder zurück gewandelt werden, aber es scheitert doch die Übergabe mit den Parametern bzw. FieldsByName('Feldname').AsGuid :=

Wenn ich in der zweiten Tabelle das Feld nicht als uuid definiere sondern als varchar(mit ausreichender Länge) dann kann ich mit FieldByName('Spalte').AsString:= die in einen String verwandelte uuid einsetzen.

Ein AsGuid gibt's nicht, so wie es As String oder AsInteger gibt.

Aber jetzt dämmert's mir wo Ihr hinwollt...

Ich kann mit INSERT INTO vermutlich die zurückverwandelte uuid in die Tabelle einfügen. Ich hab die ganze Zeit an Parameter gedacht. Ich Idiot!!

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6199
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: Allgemeines zum Umgang mit Datenbanken

Beitrag von af0815 »

ErnstVolker hat geschrieben:
Sa 8. Apr 2023, 16:36
Dummerweise habe ich in der Tabelle wo die uuid wieder hinein soll auch den Datentyp uuid verwendet. Klar kann mit StringToGUID wieder zurück gewandelt werden, aber es scheitert doch die Übergabe mit den Parametern bzw. FieldsByName('Feldname').AsGuid :=
Es kann sein, das der FPC den Datentyp GUID nicht kennt. Dann wird es klarerweise etwas komplizierter. Bei MS-SQL ist der GUID ein 16byte binär Value Type. Damit kann man aktuell vermutlich nur über string gehen. Muss ich selbst mal nachsehen.#

Edit: ftGUID gibt es, es wird aber so wie es in der fcl-db aussieht als String erwartet und auch als String zurückgegeben.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

charlytango
Beiträge: 843
Registriert: Sa 12. Sep 2015, 12:10
OS, Lazarus, FPC: Laz stable (2.2.6, 3.x)
CPU-Target: Win 32/64, Linux64
Wohnort: Wien

Re: Allgemeines zum Umgang mit Datenbanken

Beitrag von charlytango »

hmm...

@ErnstVolker -> Wie groß soll diese Firebird-DB denn werden? Oder ist GUID jetzt eine akademische Fragestellung/Herausforderung?

Ich kann der Idee GUID als Datentyp für PK eigentlich nix abgewinnen.

Seit seit mehr als 3 Dekaden baue ich an Datenbanken rum (also auch an relativ umfangreichen wie SMS Provisioning für Telekom Provider) und bin bisher immer mit Integer als PK ausgekommen.

Solange die DB die PKs vergibt brauchte ich bisher keine GUIDs.
Wenns keine intellektuelle Herausforderung oder ein Kundenwunsch ist, sollte int doch ausreichen und damit wäre die Kuh vom Eis???

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6199
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: Allgemeines zum Umgang mit Datenbanken

Beitrag von af0815 »

GUID als PK beginnt die Vorteile in replizieren DBs oder DBs an verschiedenen Standorten auszuspielen. Da der PK nicht nur DB unique sondern generell Unique ist.

Bei der Betrachtung einer Datenbank alleine ohne viel Replikation ist der Integer PK sicher einfacher und ausreichend. Er kann dir aber einen gewissen Kummer bereiten bei Road warrior DBs die ihre Daten erst später in die Hauptdatenbank einpflegen.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Antworten