Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Ersten Wert in die DB schreiben und sofort abfragen, bevor andere geschrieben werden? (https://www.delphipraxis.net/178867-ersten-wert-die-db-schreiben-und-sofort-abfragen-bevor-andere-geschrieben-werden.html)

OrNEC 1. Feb 2014 12:44

Datenbank: SQLite • Version: 3 • Zugriff über: SQLiteSimpleDelphi-Wrappers von Tim Anderson

Ersten Wert in die DB schreiben und sofort abfragen, bevor andere geschrieben werden?
 
Hallo,

ich komme bei folgendem nicht mehr weiter. Ich möchte in die DB 8 Angaben zu einem Radiosender abspeichern, zwei davon sind Comboboxen mit der Auswahl von Sprache und Kategorie. Nun muss ich schon vor dem Abspeichern wissen welche ID der Sprache und Kategorie ich dem Sender zuweisen soll, wenn diese gerade erst mit allen anderen Angaben erst erstellt werden? Weiß gar nicht wie ich das richtig beschreibe soll... auf jeden Fall ich muss die ersten zwei Werte in die Tabelle speichern, dann die ID dieser Werte holen, und mit anderen Angaben zu dem Sender verknüpft abspeichern.

Wie geht das eigentlich? Mit dem Trigger?

vagtler 1. Feb 2014 12:51

AW: Ersten Wert in die DB schreiben und sofort abfragen, bevor andere geschrieben wer
 
Stichworte Transaction und Last Inserted ID.

Perlsau 1. Feb 2014 14:52

AW: Ersten Wert in die DB schreiben und sofort abfragen, bevor andere geschrieben wer
 
@OrNEC:

Wenn du ComboBoxen zur Auswahl von Sprache und Kategorie einsetzt, ist das im Grunde kontraproduktiv. Verwende doch besser gleich eine TDBLookUpComboBox, verbinde sie entsprechend mit deiner Haupttabelle und der jeweiligen Untertabelle und du hast die ID von Sprache bzw. Kategorie automatisch in der Tabelle.

Du kannst dir ja mal als Beispiel das Waffenbuch (elektronisches Journal zum Eintrag von An- und Verkäufen scharfer, meldungspflichtiger Schußwaffen) von meiner Site runterladen. Dort werden beim Editieren bzw. Neuanlegen von Datensätzen in der Haupttabelle an allen Comboboxen, die auf Subtabellen verweisen, entsprechende Buttons eingeblendet, um bei Bedarf z.B. einen neuen Waffentyp oder ein neues Kaliber anlegen zu können. (Die beiligende Access-Datenbank, mit der ich das damals entwickelt hatte, enthält zahlreiche frei erfundene Beispieldatensätze zur Veranschaulichung.)

OrNEC 1. Feb 2014 15:29

AW: Ersten Wert in die DB schreiben und sofort abfragen, bevor andere geschrieben wer
 
Zitat:

Zitat von Perlsau (Beitrag 1246250)
@OrNEC:

Wenn du ComboBoxen zur Auswahl von Sprache und Kategorie einsetzt, ist das im Grunde kontraproduktiv. Verwende doch besser gleich eine TDBLookUpComboBox, verbinde sie entsprechend mit deiner Haupttabelle und der jeweiligen Untertabelle und du hast die ID von Sprache bzw. Kategorie automatisch in der Tabelle.

Jah... ich möchte keine DB-Komponente von Delphi verwenden, ich schreibe alles mit Standardkomponenten, so das es auch mit Delphi Versionen ohne DB-Unterstützung läuft oder mit Lazarus. Muss mir also was anderes ausdenken. :gruebel:

Aber danke Dir trotzdem! :thumb:

Perlsau 1. Feb 2014 15:42

AW: Ersten Wert in die DB schreiben und sofort abfragen, bevor andere geschrieben wer
 
Zitat:

Zitat von OrNEC (Beitrag 1246260)
Jah... ich möchte keine DB-Komponente von Delphi verwenden, ich schreibe alles mit Standardkomponenten, so das es auch mit Delphi Versionen ohne DB-Unterstützung läuft oder mit Lazarus. Muss mir also was anderes ausdenken. :gruebel:

TDBLookUpComboBox ist eine Standard-Komponente! Das ist derzeitiger Standard. Lazarus verfügt übrigens ebenfalls über Standard-DB-Komponenten. Projekte, die mit Delphi-Versionen entwickelt wurden, sind entgegen deiner Andeutung jedoch nicht kompatibel mit Lazarus! Daher solltest du dich entscheiden, ob du für alte Delphi-Versionen entwickelst oder dann doch lieber gleich in Lazarus, wo dir – insbesondere wenn du CodeTyphon einsetzt – zahlreiche Komponenten zur Verfügung stehen, die sehr wohl dem heutigen Standard entsprechen, u.a. auch Datenbank-Komponenten wie Datasets, Connectoren und dergleichen.

Wenn du jedoch weiterhin mit obsoleten Mitteln programmieren möchtest – also keine Datasets, kein direkter SQL-Zugriff auf die DB usw. – dann mußt tatsächlich du dir was überlegen, obwohl du im Grunde eigentlich möchtest, das wir hier was für dich überlegen :lol:

OrNEC 1. Feb 2014 15:50

AW: Ersten Wert in die DB schreiben und sofort abfragen, bevor andere geschrieben wer
 
Zitat:

Zitat von Perlsau (Beitrag 1246261)
Wenn du jedoch weiterhin mit obsoleten Mitteln programmieren möchtest – also keine Datasets, kein direkter SQL-Zugriff auf die DB usw. – dann mußt tatsächlich du dir was überlegen, obwohl du im Grunde eigentlich möchtest, das wir hier was für dich überlegen :lol:

Ja ich werde erst mal weiter mit obsoleten Mitteln programmieren. :-D Es wird gehen, hab schon ne Idee.

blawen 1. Feb 2014 16:24

AW: Ersten Wert in die DB schreiben und sofort abfragen, bevor andere geschrieben wer
 
Zitat:

Zitat von OrNEC (Beitrag 1246263)
Ja ich werde erst mal weiter mit obsoleten Mitteln programmieren. :-D Es wird gehen, hab schon ne Idee.

vagtler hat Dir ja schon einen Ansatz gegeben.

Delphi-Quellcode:
{ "Protokoll"-Rumpfdatensatz generieren }
quSpeichern.SQL.Text := 'Insert Into ..hier steht Dein SQL-Code..';
quSpeichern.ExecSQL;

{ Den neu erstellten Datensatz finden und die Datensatz ID bestimmen }   
quSpeichern.SQL.Text := 'Select LAST_INSERT_ID()';
quSpeichern.Active  := True;
iDatensatz          := quSpeichern.Fields[0].AsInteger;

Perlsau 1. Feb 2014 17:32

AW: Ersten Wert in die DB schreiben und sofort abfragen, bevor andere geschrieben wer
 
Er möchte aber doch keine DB-Komponenten von Delphi verwenden ... :gruebel:

mkinzler 1. Feb 2014 17:41

AW: Ersten Wert in die DB schreiben und sofort abfragen, bevor andere geschrieben wer
 
Zitat:

Zitat von Perlsau (Beitrag 1246270)
Er möchte aber doch keine DB-Komponenten von Delphi verwenden ... :gruebel:

Das ändert aber nichts am grundsätzlichen Vorgehen. Ich kenne den verwendeten Wrapper nicht; die benötigten SQL Statements sollten aber die selben sein.

Perlsau 1. Feb 2014 18:34

AW: Ersten Wert in die DB schreiben und sofort abfragen, bevor andere geschrieben wer
 
Naja, wenn man mit SQL arbeiten kann, sollte man eher so vorgehen:

Delphi-Quellcode:
MyQuery.SQL.Text := 'select * from Tabelle_Sprache where Sprache = ' + QuotedStr(Edit_Sprache.Text);
MyQuery.Open;
if MyQuery.RecordCount = 0 then
begin
  // Hier die Insert-Methode einfügen/aufrufen
end;
oder gleich mit Locate arbeiten:
Delphi-Quellcode:
If Not MyQuery.Locate('Sprache',Edit_Sprache.Text,[] then ...
Sonst hat man hinterher unzählige Einträge derselben Sprache in der Tabelle.

Leider hab ich keinen blassen Schimmer, wie der Zugriff über die SQLiteSimpleDelphi-Wrappers von Tim Anderson abläuft und kann daher nur spekulieren. Gibt es in diesem Wrapper die Möglichkeit, SQL einzusetzen?

blawen 1. Feb 2014 19:09

AW: Ersten Wert in die DB schreiben und sofort abfragen, bevor andere geschrieben wer
 
Zitat:

Zitat von Perlsau (Beitrag 1246270)
Er möchte aber doch keine DB-Komponenten von Delphi verwenden ... :gruebel:

Woraus schliesst Du, dass es sich um Delphi-Komponenten handelt (Das Beispiel wurde u.a. um ein "z" gekürzt (zeos))?

Zitat:

Zitat von Perlsau (Beitrag 1246272)
Naja, wenn man mit SQL arbeiten kann, sollte man eher so vorgehen:

Delphi-Quellcode:
MyQuery.SQL.Text := 'select * from Tabelle_Sprache where Sprache = ' + QuotedStr(Edit_Sprache.Text);
MyQuery.Open;
if MyQuery.RecordCount = 0 then
begin
  // Hier die Insert-Methode einfügen/aufrufen
end;

In meinem Beispiel wurde nur der Insertteil aufgeführt. Die Frage von OrNEC bezieht sich ja lediglich auf das Feststellen der neuen Datensatznummer.

Sir Rufo 1. Feb 2014 20:53

AW: Ersten Wert in die DB schreiben und sofort abfragen, bevor andere geschrieben wer
 
Nochmal an alle, die es in der Hitze der Diskussion nicht mitbekommen haben:

Der Zugriff auf SQLite erfolgt über SQLiteSimpleDelphi-Wrappers von Tim Anderson.
Da ist nix mit TDataSet, TDataSource, TDBEdit, TDBComboBox, TDB...

mschaefer 1. Feb 2014 21:37

AW: Ersten Wert in die DB schreiben und sofort abfragen, bevor andere geschrieben wer
 
So wie ich das lese möchtest Du eine Master Deteil-Kombination eintragen:

1. Masterdatesatz eintragen
2. ID(´s) holen7den
3. Detail-Datensatz mit Referenz (der ID ('s) der Master-Tabelle) speichern.

Man kann dafür die SQL-Eingenschaften bei Query-Komponenten nehmen, sind bei Lazarus und Delphi-Versionen mit DB Unterstützung dabei oder das oben aufgeführten Paket. SQLite hat keine Sequences oder Generatoren und daher ist der Ansatz mit Trigger suboptimal, aber SQLite hat zum Ausgleich "AutoIncrement", sodass folgendes geht:

Code:
   CREATE TABLE COMPANY(
   ID INTEGER PRIMARY KEY  AUTOINCREMENT,
   NAME          TEXT     NOT NULL,
);
Master-Tabelle mit Auto-Increment anlegen.
Code:
   CREATE TABLE Employee(
   ID INTEGER PRIMARY KEY  AUTOINCREMENT,
   NAME          TEXT     NOT NULL,
   RID_Company    INT      NOT NULL,
);
Detail-Tabelle mit Auto-Increment und Referenz-ID-Feld anlegen.


Code:
INSERT INTO COMPANY (NAME )
VALUES ( 'Neptum AG' );
Master Datensatz einfügen, wobei das Auto-Inc-Feld nicht angegeben wird


Code:
Select max(ID ) as MAXID from COMPANY
Letzte Höchste ID holen (geht vielleicht per SQLite-Funktion eleganter... )


Code:
INSERT INTO Employee (NAME )
VALUES ( 'Kapt´n Nelson', :MAXID  );
Master Datensatz einfügen, wobei Max-ID in einer Variablen übergeben wird.


Das würde ich so als Weg sehen, wobei ich mit meinen VorPostern übereinstimme,
dass dies nicht abhängig von einer bestimmten Komponente ist.

Grüße in die Runde.

OrNEC 1. Feb 2014 21:47

AW: Ersten Wert in die DB schreiben und sofort abfragen, bevor andere geschrieben wer
 
Ich glaube genau das habe ich gesucht. Danke! :thumb:
Nun muss ich das Praktisch bzw. Syntaktisch richtig umsetzen!

sx2008 1. Feb 2014 22:05

AW: Ersten Wert in die DB schreiben und sofort abfragen, bevor andere geschrieben wer
 
Ohne Autoinc-Feld klappt das aber besser.
Dann muss man eben den Wert des Primärschlüsselfelds vorher ermitteln und kurz in einer Variablen merken.
SQL-Code:
Select max(ID)+1 as NewID from COMPANY
Das ist besser als hinterher nachzuschauen welchen Datensatz man gerade eben eingefügt hat.
Insbesondere wenn man mal mit einer Multiuserdatenbank arbeitet können Autoinc-Felder zu ganz bösen Fehlern führen.

Medium 2. Feb 2014 03:50

AW: Ersten Wert in die DB schreiben und sofort abfragen, bevor andere geschrieben wer
 
Öhm, wie kann ein client-basierter Index in einer Multi-User Umgebung "besser" sein als ein vom Server vergebener AutoInc-Index? Oder soll ich am besten gleich die ganze Tabelle locken wenn ein Client darin Inserted? :shock:

Davon ab habe ich mir schon oft eine vom DBMS direkt unterstütze Rückgabe der ID eines soeben eingefügten Datensatzes gewünscht. Am liebsten in so einer Form von einer DB-Komponente unterstützt:
Delphi-Quellcode:
MyQuery.SQL.Text := 'INSERT INTO foo VALUES (:bar)';
...
lastIndex := MyQuery.ExecuteWithResult('indexFieldName'); // Exception wenn das genannte Feld kein AutoInc, oder das Statement kein INSERT ist
Das würde zum einen die unhandlichen Abfragen von LastInsertID, sowie die Notwendigkeit alles zugehörige in eine Transaktion zu verpacken sparen.

So eine Methode ließe zudem noch so Nettigkeiten zu wie 'SELECT * FROM foo WHERE bar=:bla', für den Fall dass man genau einen Datensatz als Ergebnis erwartet, und den Wert nur einer Spalte haben will. Exception bei 0 oder >1 Ergebnissen, sowie wenn das gefragte Feld nicht im Ergebnis vorkommt. Spart das Open und den Umweg über die Abbildung auf Fields[]. Ich frage mich fast, warum das sich so nie etabliert hat.

himitsu 2. Feb 2014 05:58

AW: Ersten Wert in die DB schreiben und sofort abfragen, bevor andere geschrieben wer
 
Zitat:

Zitat von sx2008 (Beitrag 1246280)
Insbesondere wenn man mal mit einer Multiuserdatenbank arbeitet können Autoinc-Felder zu ganz bösen Fehlern führen.

Gerade da sorgen sie doch erst Recht für zuverlässige Indize-Felder?
Aber, man muß wenigstens den "richtigen" Master-Index wieder auslesen, wenn man dazu den Detail-Datensatz anlegen möche.

SQL-Code:
SELECT Max(ID) FROM Master
, nach dem Anlegen des Master-Datensatzes, ist da also totaler Mist, da dort natürlich die falsche ID gelesen werden kann, wenn zwischenzeitlich ein anderer User auch da was eingetragen hat.
Wenn man die IDs im Clienten bestimmt, dann weiß man zwar vor dem Anlegen des Master-Datensatzes, wie dessen ID sein wird und kann sie "sicher" für den Detail-Datensatz nutzen, aber dann muß man womöglich im Clienten extra eine Fehlerbehandlung integrieren, da die Datenbank entsprechend reagiert, wenn zwischen dem
SQL-Code:
SELECT MAX
und dem
SQL-Code:
INSERT
ein anderer User schneller war und seinen Master-Datensatz anlegete und man nun selber natürlich eine doppelte ID anlegen möchte.

LAST_INSERT_ID ist doch Session an die Sessions gebunden?
Wenn ja, dann ist es an die eigene Verbindung gebunden und den darüber erstellten Datensatz, womit man dann seine ID bekommt, auch wenn jemand Anderes inzwischen gepostet hat.

Einige DBMS kennen sowas wie
SQL-Code:
INSERT INTO table (id, value) VALUES (:id, :value) RETURNING id
, was quasi Folgendem entspricht, als "eine" zusammenhängende Abfrage.
SQL-Code:
INSERT INTO table (id, value) VALUES (:id, :value);
SELECT LAST_INSERT_ID();
SQLite aber anscheinend nicht.



Kennt SQLite eigentlich auch Referenzen?
Um gültige Werte der Master-IDs in der Detail-Tabelle sicherzustellen.

Sir Rufo 2. Feb 2014 06:17

AW: Ersten Wert in die DB schreiben und sofort abfragen, bevor andere geschrieben wer
 
Doku zu SQLite Last Insert Rowid

Ja, das hängt immer an der Session - weil es sonst nutzlos wäre ;)

Doku zu SQLite Foreign Key Support


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:56 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz