Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi SQL Automatisch zugeteilte Id ermitteln. (https://www.delphipraxis.net/181067-sql-automatisch-zugeteilte-id-ermitteln.html)

Bladefire 12. Jul 2014 14:32

Datenbank: MySQL • Version: 5 • Zugriff über: k. A.

SQL Automatisch zugeteilte Id ermitteln.
 
Hallo,

Ich möchte ein Programm machen das etwas in eine SQL Datenbank schreibt. Der Datensatz bekommt automatisch von der Datenbank eine id zugeteilt. Nun möchte ich diese Id meinen Programm irgendwie mitteilen.

Jedoch weiß ich nicht wie ich das machen soll.

- ich kann nicht einfach den letzten eingetragenen Datensatz auslesen, da es möglich ist, dass ein anderes Programm etwas in der Zwischenzeit in die Datenbank - Tabelle Schreibt.

Wie soll / kann ich dies realisieren?

Lg Simon

jfheins 12. Jul 2014 14:51

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Die meisten Datenbanken haben dafür eine Funktion wie LAST_INSERT_ID oder ähnliches.

Perlsau 12. Jul 2014 17:21

AW: SQL Automatisch zugeteilte Id ermitteln.
 
@Bladefire:

Gleich nach dem Posten bzw. Insert ist der bearbeitete bzw. gerade eingefügte Record der aktuelle Datensatz. Da kannst du doch einfach abfragen, welcher Wert in deinem Id-Feld steht:

Delphi-Quellcode:
AktuelleId := MyDataset.FieldByName('IdFeld').asInteger;
Zur Anzeige in der Statusbar mache ich das in den meisten DB-Anwendungen sogar grundsätzlich, und zwar mittels des Ereignisses AfterScroll. Dort wird dann die Id ausgelesen und ein Ereignis generiert, das meien Statusbar aktualisiert.

dummzeuch 12. Jul 2014 19:45

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Zitat:

Zitat von Perlsau (Beitrag 1265322)
@Bladefire:

Gleich nach dem Posten bzw. Insert ist der bearbeitete bzw. gerade eingefügte Record der aktuelle Datensatz. Da kannst du doch einfach abfragen, welcher Wert in deinem Id-Feld steht:

Delphi-Quellcode:
AktuelleId := MyDataset.FieldByName('IdFeld').asInteger;

Funktioniert das inzwischen zuverlaessig? Ich erinnere mich, dass ich daran mal verzweifelt bin - das muss irgendwann in den 90ern gewesen sein - und schliesslich eine Tabelle mit IDs eingefuehrt habe, mit einem Datensatz pro Tabelle, in dem die jeweils naechste zu benutzende ID stand. Diesen Record habe ich dann gelockt, ausgelesen, die ID erhoeht und gespeichert. Das funktionierte dann wenigstens. AutoInc Felder funktionierten spaeter dann fuer Access- und MSSQL mal, wenn man Cursor auf clUseServer gesetzt hat. Aber ich habe immernoch im Hinterkopf, dass sie nicht sicher sind. Mein letztes groesseres Datenbank-Projekt ist allerdings schon wieder ein paar Jahre her.

Perlsau 13. Jul 2014 01:38

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Das funktioniert 100 % zuverlässig, zumindest meiner Erfahrung nach, ich kenne das gar nicht anders, und zwar bei allen DBMS, die ich jemals in Verwendung hatte, als da wären:
Firebird, MsSQL, MySQL, ProstGreSQL, MsAccess. Wäre dem nicht so, wären DBMS nicht wirklich einsatzfähig. Ob DBMS vor 20 Jahren unzuverlässig waren, kann ich nicht beurteilen, hatte damals noch nichts damit am Hut. Und wenn du's nicht glaubst, probier's doch einfach mal aus, wirst schon sehen (sollte man sowieso immer machen, wenn man Ratschläge aus Foren erhält).

Dejan Vu 13. Jul 2014 08:01

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Ob das so funktioniert, hängt nicht vom RDBMS ab, sondern vom Provider (Zeus, ADO, dbExpress, DAC) und da gab es -zumindest bei ADO- früher wirklich Probleme bzw. hat das nicht funktioniert. Früher. Jetzt ist das alles kein Problem mehr. Man muss nur sicherstellen, das der Provider erkennt, das es sich um ein AutoInc-Feld handelt bzw. das persistente Feld entsprechend deklarieren. Firebird z.B. kennt keinen AutoInc-Datentypen. Da erstellt man einen Generator und stellt im Provider das Feld entsprechend ein.

Perlsau 13. Jul 2014 12:57

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Mit all den von dir genannten DB-Komponenten funktioniert genau das: Wenn ich einen neuen Datensatz in eine Datensatz-Menge einfüge, bleibt dieser Datensatz der aktuelle, solange ich keinen anderen Datensatz einfüge oder anwähle. Das hat nichts mit Auto-Inc-Feldern zu tun. Im Übrigen gibt es Zeus nicht, das heißt Zeos.

Dejan Vu 13. Jul 2014 14:12

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Ach, Zeos, genau. Ich wollte dir nach widersprechen, sondern nur darauf hinweisen, das es Sache des Providers ist, sich um die Aktualisierung von Daten zu kümmern. Ähnliches gilt ja auch für einen Zeitstempel, der vom Server gesetzt wird, weil man z.B. in einer Spalte den Zeitpunkt der letzten Änderung haben will, und da ist es sinnvoll, die Serverzeit zu setzen (per Trigger). Nun muss aber dieser Wert wieder zum Client...

Und das es der aktuelle Datensatzzeiger ist, liegt daran, das der aktuelle Record eingefügt/aktualisiert wird, wenn ein Post stattfindet. Und das findet bei einem Recordwechsel statt (dann ist der eben noch aktuelle DS zwar nicht mehr aktuell, aber ich weiss ja, was Du meinst), oder man ruft explizit Post auf.

Es gibt ja auch den Modus, das man die Änderungen erst lokal durchführt (für beliebig viele Records) und dann die Änderungen in einem Abwasch zum Server schickt. Dann gibt es ja keinen 'aktuellen' Datensatzzeiger. bzw. gibt es einen, aber es werden auch andere Records aktualisiert.

Wie ist denn die ID-Spalte bei einer Verbindung zu Firebird deklariert, damit sie nach einem INSERT weiß, welche ID vom RDBMS vergeben wurde?

Perlsau 13. Jul 2014 15:37

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Zitat:

Zitat von Dejan Vu (Beitrag 1265377)
Wie ist denn die ID-Spalte bei einer Verbindung zu Firebird deklariert, damit sie nach einem INSERT weiß, welche ID vom RDBMS vergeben wurde?

Was meinst du damit? Die Id-Spalte ist in Firebird deklartiert und nicht im Client, der die Verbindung zur FB-Datenbank herstellt, z.B.:
Code:
ID_ZUSATZKLASSE INTEGER NOT NULL
ALTER TABLE ZUSATZKLASSE ADD CONSTRAINT PK_ZUSATZKLASSE PRIMARY KEY (ID_ZUSATZKLASSE);
Willst du AutoInc-Funktionalität, erstellst du dir einen BeforeInsert- oder AfterInsert-Trigger, der einen Generator aufruft, von dem er sich den neuen Wert holt und in die Id-Spalte einträgt. IbExpert erledigt das automatisch, wenn man beim Erstellen der Tabelle die AutoInc-Checkbox aktiviert.

Vom Client aus kannst du dann – bei BeforeInsert – die Id-Spalte bereits vor dem Posten auslesen. Hast du AfterInsert eingestellt, mußt du dir mit dem Auslesen des aktuellen Generatorwertes behelfen:
Code:
select GEN_ID(GEN_ZUSATZKLASSE_ID,0) from RDB$DATABASE
... wobei der zweite Parameter den Increment-Wert darstellt.

DeddyH 13. Jul 2014 16:48

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Firebird kennt (IIRC ab der Version 2.0) eine RETURNING-Klausel, die genau für solche Zwecke gedacht ist, siehe z.B. hier.

Perlsau 13. Jul 2014 17:39

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Klar, wenn man via SQL-Befehlen direkte Inserts absetzt. Arbeitest du jedoch mit einer Datenmenge (Query), mittels derer du einen neuen Datensatz anzulegen gedenkst, nützt dir die Returning-Klausel nichts, denn Query.Append ist eine Procedure.

Dejan Vu 13. Jul 2014 18:10

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Ich muss mein Deutsch verbessern: Was ich meine, ist etwas wie die Property 'AutoGenerateValue' in einem TIntegerField. Normalerweise erzeugt der Provider einen Befehl, à la:
Code:
INSERT INTO Foo (ID,Value) VALUES (0,'Bar')
Der weiß doch nicht, das ID ein AutoInc-Feld ist. Erst wenn ich die o.g. Property entsprechend setze, wird der Befehl anders gerendert:
Code:
INSERT INTO Foo (Value) VALUES ('Bar') RETURNING ID
ADO kann die 'AutoGenerateValue' selbst richtig setzen, weil ja aus der Schemainformation (zumindest im SQL-Server) hervorgeht, das ID eine IDENTITY-Spalte ist. Nur, woran erkennt der Provider nun, das das Feld 'ID' bei Firebird eine Art AutoInc-Feld ist? Er wird ja wohl kaum die Trigger parsen...

Perlsau 13. Jul 2014 18:16

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Wenn deine Datenbank AutoInc in irgend einer Form unterstützt (bei Firebird z.B. über AfterInsert- bzw. BeforeInsert-Trigger und entsprechendem Generator) benötigst du keine clientseitige Initialisierung dieser Funktionalität, denn der Trigger löst automatisch beim Insert aus, und zwar völlig unabhängig vom Provider oder dem Sender des SQL-Befehhls.

Unterstützt dein DBMS das nicht, bieten einige DB-Komponenten die Möglichkeit, das via Client zu erledigen. Die entsprechenden Einstellungen zu wählen ist Aufgabe des Entwicklers. Der Provider muß nicht "wissen", ob es sich um ein "AutoInc-Feld" handelt.

Und ja: Kommuniziert man über Sachgebiete, die exakte Darstellungen erfordern (wie beispielsweise Mathematik oder eben auch eine Programmiersprache wie Pascal), ist es nicht wirklich zielführend, weiterhin die gewohnte Umgangssprache einzusetzen. Ohne ausreichende Kenntnis der Fachbegriffe und ihrer Bedeutung versagt man dann regelmäßig beim Versuch, Sachverhalte korrekt darzustellen.

Uwe Raabe 13. Jul 2014 18:19

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Zitat:

Zitat von Dejan Vu (Beitrag 1265399)
Nur, woran erkennt der Provider nun, das das Feld 'ID' bei Firebird eine Art AutoInc-Feld ist? Er wird ja wohl kaum die Trigger parsen...

Aus diesem Grund gibt es ja
Delphi-Quellcode:
TAutoIncField
bzw. den DataType
Delphi-Quellcode:
ftAutoInc
. Der Provider muss das nur passend zum Server umsetzen. Nicht alle können bzw. machen das. DbExpress hat da so seine Problemchen während FireDAC das ganz gut hinkriegt.

Sir Rufo 13. Jul 2014 18:28

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1265401)
Zitat:

Zitat von Dejan Vu (Beitrag 1265399)
Nur, woran erkennt der Provider nun, das das Feld 'ID' bei Firebird eine Art AutoInc-Feld ist? Er wird ja wohl kaum die Trigger parsen...

Aus diesem Grund gibt es ja
Delphi-Quellcode:
TAutoIncField
bzw. den DataType
Delphi-Quellcode:
ftAutoInc
. Der Provider muss das nur passend zum Server umsetzen. Nicht alle können bzw. machen das. DbExpress hat da so seine Problemchen während FireDAC das ganz gut hinkriegt.

Pssst, sag nicht sowas, das funktioniert immer ohne Wenn und aber, egal womit man darauf zugreift, in Ehrlichkeit, Amen :mrgreen:

Dejan Vu 13. Jul 2014 18:38

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Ist schon klar. Nur ganz so automatisch, wie Perlsau das gesagt hat, scheint es dann doch nicht zu gehen. Die Felder muss man dann ggf. manuell anpassen.

mkinzler 13. Jul 2014 19:13

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Das RETURNING von FireBird wird ihm be der Verwendung von MySQL wenig bringen. In diesem Fall würde ich mich auch nicht darauf verlassen, dass der Datensatzzeiger nach dem Insert aauf dem richtigen Datensatz steht, sondern wie in der 1. Antwort beschrieben die saubere Variante wählen.

DeddyH 13. Jul 2014 19:48

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Das RETURNING hatte ich erwähnt, als von Firebird die Rede war. Weshalb man unter MySQL LAST_INSERT_ID verwenden sollte, ist in dem verlinkten Artikel aus der ersten Antwort erschöpfend beschrieben.

Perlsau 14. Jul 2014 00:26

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Zitat:

Zitat von Dejan Vu (Beitrag 1265404)
Ist schon klar. Nur ganz so automatisch, wie Perlsau das gesagt hat, scheint es dann doch nicht zu gehen. Die Felder muss man dann ggf. manuell anpassen.

Vielleicht solltest du nicht nur deine Ausdruckfähigkeiten verbessern, sondern auch deine Lesekompentenz: Ich habe ausdrücklich geschrieben, daß die Erzeugung einer fortlaufenden Id genau dann automatisch funktioniert, wenn das betreffende DBMS das unterstützt. Auf die Gefahr hin, mich zu wiederholen:

Wenn deine Datenbank AutoInc in irgend einer Form unterstützt (bei Firebird z.B. über AfterInsert- bzw. BeforeInsert-Trigger und entsprechendem Generator) benötigst du keine clientseitige Initialisierung dieser Funktionalität, denn der Trigger löst automatisch beim Insert aus, und zwar völlig unabhängig vom Provider oder dem Sender des SQL-Befehhls.

Automatisch bedeutet hier nicht halbautomatisch, sondern in der Tat ganz automatisch ohne weiteres Zutun. Um jedoch auf einen tatsächlichen Fall, bei dem es nicht wie erwartet ganz automatisch funktioniert, eingehen zu können, wäre es hilfreich, wenn du ein wenig mehr dazu verraten würdest. Ich habe diesen Fall mit den von mir genannten DBMS in vielen Jahren der Datenbankanwendungsentwicklung noch kein einziges Mal erlebt, nicht mal ansaztweise, weder mit Ado, IbDac, dbExpress, FibPlus, Zeos oder UIB. Mit anderen Worten: Meine Ids wurden bislang immer verläßlich erzeugt.

Nachtrag:

Wenn irgendwelche obsolte DBMS hier Fehlverhalten zeigten, sollten sie nicht mehr eingesetzt werden. Insbesondere der Einsatz der völlig veralteten Borland Database Engine sollte, will man zukunftsfähige und zuverlässige DB-Anwendungen entwickeln, unbedingt vermieden werden.

mse1 14. Jul 2014 08:07

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Zitat:

Zitat von Perlsau (Beitrag 1265423)
Ich habe diesen Fall mit den von mir genannten DBMS in vielen Jahren der Datenbankanwendungsentwicklung noch kein einziges Mal erlebt, nicht mal ansaztweise, weder mit Ado, IbDac, dbExpress, FibPlus, Zeos oder UIB. Mit anderen Worten: Meine Ids wurden bislang immer verläßlich erzeugt.

ID's werden im Server sicher verlässlich erzeugt. Aber kannst du wirklich die Hand dafür ins Feuer legen, dass *alle* client libraries und Komponenten die erzeugte ID korrekt und im richtigen Moment im Feldinhalt abbilden?
MSEgui z.B. macht dies automatisch für das primary key Feld via "last insert id" wenn die DB es unterstützt. Für andere DB's muss entweder "tsequencelink" verwendet werden oder das Feld-flag "of_refreshinsert" und eventuell "of_refreshupdate" gesetzt werden, welche die "returning" Option im SQL-Kommando aktivieren.

Perlsau 14. Jul 2014 08:36

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Zitat:

Zitat von mse1 (Beitrag 1265428)
ID's werden im Server sicher verlässlich erzeugt.

Sag ich doch ständig!

Zitat:

Zitat von mse1 (Beitrag 1265428)
Aber kannst du wirklich die Hand dafür ins Feuer legen, dass *alle* client libraries und Komponenten die erzeugte ID korrekt und im richtigen Moment im Feldinhalt abbilden?

Keine Ahnung, was du mit "korrekt" meinst bzw. wie eine inkorrekte Darstellung (Abbildung) aussehen könnte.

Wann ist der "richtige Moment"?

Zitat:

Zitat von mse1 (Beitrag 1265428)
MSEgui z.B. macht dies automatisch für das primary key Feld via "last insert id" wenn die DB es unterstützt. Für andere DB's muss entweder "tsequencelink" verwendet werden oder das Feld-flag "of_refreshinsert" und eventuell "of_refreshupdate" gesetzt werden, welche die "returning" Option im SQL-Kommando aktivieren.

MSEgui? This page was last modified on 12 December 2013, at 12:39

Bis jetzt hat hier noch keiner eine Situation beschrieben, in der die Zuverlässigkeit der Erzeugung einer Id nicht gewährleistet wäre. Ich lese immer nur Andeutungen und "von früher".

Übrigens: Weder Hände noch andere Extremitäten sollte man ins Feuer legen, auch nicht, um irgend etwas zu beweisen. Ich bin nicht dafür haftbar zu machen, wenn irgend jemand eine Konstruktion zusammenbastelt, die irgendwelche fehlerhafte PK-Ids liefert oder anzeigt. Ich hatte damit wie bereits erähnt noch niemals auch nur das geringste Problem. Da gibt's im Zusammenhang mit Datenbank-Anwendungen ganz andere Dinge, die problematisch sein können.

mkinzler 14. Jul 2014 08:56

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Das es bisher und jetzt funktioniert ist aber keine Garantie, dass es auch in der Zukunft so funktioniert. Deshaln würde ich den dokumentierten Weg über die vom DBMS bereitgestellten Funktionen gehen.

Blup 14. Jul 2014 09:20

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Abseits des eigentlichen MySql-Themas:

Zitat:

Zitat von Perlsau (Beitrag 1265386)
Willst du AutoInc-Funktionalität, erstellst du dir einen BeforeInsert- oder AfterInsert-Trigger, der einen Generator aufruft, von dem er sich den neuen Wert holt und in die Id-Spalte einträgt. IbExpert erledigt das automatisch, wenn man beim Erstellen der Tabelle die AutoInc-Checkbox aktiviert.

Vom Client aus kannst du dann – bei BeforeInsert – die Id-Spalte bereits vor dem Posten auslesen. Hast du AfterInsert eingestellt, mußt du dir mit dem Auslesen des aktuellen Generatorwertes behelfen:
Code:
select GEN_ID(GEN_ZUSATZKLASSE_ID,0) from RDB$DATABASE
... wobei der zweite Parameter den Increment-Wert darstellt.

Das ist so nicht ganz richtig.
Auch der BeforeInsert-Trigger der Datenbank wirkt erst, nachdem der Datensatz per Post an den Server übergeben wurde.
Es gibt allerdings Komponenten die den Wert solcher Spalten selbst vorab erzeugen.
Dafür muss dann der für diese Spalte zuständigen Generator angegeben werden.
Die Komponente erzeugt die neue ID über eine interne Abfrage und setzt dabei den Generator hoch:
Code:
select GEN_ID(GEN_ZUSATZKLASSE_ID, 1) from RDB$DATABASE
Dann wirkt aber auch der Trigger nicht mehr, da die Spalte bereits belegt ist.

Es ist dagegen fahrlässig, den Generator nur abzufragen ohne den Generatorwert hochzusetzen und sich darauf zu verlassen, dass der Trigger diese ID beim nächsten Post vergibt.
Generatoren zählen für alle Transaktion und Datenbankverbindungen. Bis zum eigenen Post kann sich der Generatorwert schon wieder geändert haben und der Trigger vergibt eine andere ID.

supermuckl 14. Jul 2014 09:31

AW: SQL Automatisch zugeteilte Id ermitteln.
 
ich hab das problem letztens in postgres so gelöst:

transaction auf
query ausführen
"id des eingefügten records auslesen" query dahinter
transaction zu

damit kommt direkt die neue id als resultset zurück

mse1 14. Jul 2014 09:40

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Zitat:

Zitat von Perlsau (Beitrag 1265430)
MSEgui? This page was last modified on 12 December 2013, at 12:39

http://sourceforge.net/projects/mseide-msegui/
Zitat:

Bis jetzt hat hier noch keiner eine Situation beschrieben, in der die Zuverlässigkeit der Erzeugung einer Id nicht gewährleistet wäre. Ich lese immer nur Andeutungen und "von früher".
Das mögliche Problem ist nicht das Erzeugen der ID sondern wie man die erzeugte ID unverzüglich zurück erhält.

p80286 14. Jul 2014 10:11

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Zitat:

Zitat von supermuckl (Beitrag 1265437)
ich hab das problem letztens in postgres so gelöst:

transaction auf
query ausführen
"id des eingefügten records auslesen" query dahinter
transaction zu

damit kommt direkt die neue id als resultset zurück

Unter Umständen könnte das ja auf allen Datenbanken, egal wieviele Benutzer im Moment zugreifen funktionieren? Und auch noch unabhängig von der eingesetzten Schnittstellensoftware?
Das kann nicht sein!:mrgreen:

Gruß
K-H

Perlsau 14. Jul 2014 11:30

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Zitat:

Zitat von Blup (Beitrag 1265435)
Das ist so nicht ganz richtig. Auch der BeforeInsert-Trigger der Datenbank wirkt erst, nachdem der Datensatz per Post an den Server übergeben wurde.

Der Generator – und ich schreibe hier wieder ausschließlich über Firebird, auch wenn ich meine, daß es sich hier um eine generelle Verfahrensweise bei allen modernen DBMS handelt – incrementiert bei BeforeInsert vor dem Posten. In die jeweilige Spalte wird dieser Wert natürlich erst nach dem Posten eingetragen:

This database also maintains a generator named EMP_NO_GEN and a Before Insert trigger named SET_EMP_NO on the EMPLOYEE table, to produce a value for this key whenever a new row is inserted. (Helen Borrie: The Firebird Book)

Wenn die Aktion (insert) nicht abgeschlossen (post) wird (was einem cancel entspricht), setzt der Trigger den einmal erhöhten Generatorwert wieder zurück (rollback):

Work performed by triggers will be rolled back if the transaction that prompted them is rolled back. (Helen Borrie: The Firebird Book)

Zitat:

Zitat von Blup (Beitrag 1265435)
Es gibt allerdings Komponenten die den Wert solcher Spalten selbst vorab erzeugen.
Dafür muss dann der für diese Spalte zuständigen Generator angegeben werden.
Die Komponente erzeugt die neue ID über eine interne Abfrage und setzt dabei den Generator hoch:
Code:
select GEN_ID(GEN_ZUSATZKLASSE_ID, 1) from RDB$DATABASE
Dann wirkt aber auch der Trigger nicht mehr, da die Spalte bereits belegt ist.

Verwechselst du da nicht was? Die Id-Spalte des neu anzulegenden Datensatzes wird erst nach dem Post belegt. Würden die DB-Komponenten den Generatorwert von sich aus hochsetzen, würde das bedeuten, daß der Generatorwert immer um 2 erhöht wird, wenn BeforeInsert oder AfterInsert in der DB gesetzt sind, denn der Trigger wird ja auch ohne entsprechende DB-Komponenten im Client allein schon durch den Insert-Befehl ausgelöst, z.B. wenn ich ein SQL-Script mit Insert-Befehlen laufen lasse.

Zitat:

Zitat von Blup (Beitrag 1265435)
Es ist dagegen fahrlässig, den Generator nur abzufragen ohne den Generatorwert hochzusetzen und sich darauf zu verlassen, dass der Trigger diese ID beim nächsten Post vergibt. Generatoren zählen für alle Transaktion und Datenbankverbindungen. Bis zum eigenen Post kann sich der Generatorwert schon wieder geändert haben und der Trigger vergibt eine andere ID.

Richtig! Für Single-User-Anwendungen spielt das jedoch keine Rolle, bei Multi-User-Anwendungen dagegen schon: Hier sollte man einfach die Id, die nach dem Posten vergeben wurde, aus der jeweiligen Id-Spalte der gerade bearbeiteten Tabelle auslesen. Sollte es irgend eine Spalte in der jeweiligen Systemtabelle geben, die diese LAST_INSERT_IDs protokolliert, besteht dasselbe Problem in einer Multi-User-Umgebung: die letzte eingefügte Id muß nicht zwangsläufig diejenige sein, die der Client eigentlich abrufen möchte – es sei denn, man verwaltet das selbst und hinterlegt in einer weiteren Spalte die entsprechende User-Id.

supermuckl 14. Jul 2014 12:31

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Zitat:

Zitat von p80286 (Beitrag 1265450)
Zitat:

Zitat von supermuckl (Beitrag 1265437)
ich hab das problem letztens in postgres so gelöst:

transaction auf
query ausführen
"id des eingefügten records auslesen" query dahinter
transaction zu

damit kommt direkt die neue id als resultset zurück

Unter Umständen könnte das ja auf allen Datenbanken, egal wieviele Benutzer im Moment zugreifen funktionieren? Und auch noch unabhängig von der eingesetzten Schnittstellensoftware?
Das kann nicht sein!:mrgreen:

Gruß
K-H

bin ich mir nicht so ganz sicher
aber es gibt halt den weg - und ob der sicher ist, hängt von der implementation der transaktion ab (transaktionsisolation)

begin;
insert into test(name) values ('something');
select CURVAL('test_id_seq');
commit;

und auch den weg (postgresql native) über
"returning"

INSERT INTO t2 (eid, ...) VALUES (...) RETURNING eid;

ob es das bei anderen DBs gibt, weiß ich nicht

mse1 14. Jul 2014 12:35

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Zitat:

Zitat von Perlsau (Beitrag 1265458)
This database also maintains a generator named EMP_NO_GEN and a Before Insert trigger named SET_EMP_NO on the EMPLOYEE table, to produce a value for this key whenever a new row is inserted. (Helen Borrie: The Firebird Book)

Wenn die Aktion (insert) nicht abgeschlossen (post) wird (was einem cancel entspricht), setzt der Trigger den einmal erhöhten Generatorwert wieder zurück (rollback):

Work performed by triggers will be rolled back if the transaction that prompted them is rolled back. (Helen Borrie: The Firebird Book)

Leider ist das für Sequenz-Werte nicht möglich:
Zitat:

As said, generators live outside of transaction control. This simply means you cannot safely “rollback” generators inside a transaction. There may be other transactions executing at the same time that change the value while your transaction runs. So once you have requested a generator value, consider it as “gone forever”.
http://www.firebirdsql.org/manual/ge...de-basics.html

Mikkey 14. Jul 2014 12:44

AW: SQL Automatisch zugeteilte Id ermitteln.
 
@supermuckl

Eine Funktion "CURVAL" dürfte es nicht durchgehend auf allen DBMS geben. Allerdings hatte ich Deinen ersten Beitrag dazu eher so verstanden:

Code:
INSERT INTO table(f1, f2) VALUES(<Schlüsselwert>, 'Blabla');
SELECT <autoincrementfield> FROM table WHERE f1=<Schlüsselwert>
Der Schlüssel muss dann natürlich eindeutig sein.

Das dürfte innerhalb einer Transaktion in jedem DBMS funktionieren, könnte bei manchen (je nach Konfiguration) aber zum Rollback führen, wenn zwei User "gleichzeitig" diese Transaktion durchführen.

mjustin 14. Jul 2014 12:59

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Zitat:

Zitat von Mikkey (Beitrag 1265464)

Code:
INSERT INTO table(f1, f2) VALUES(<Schlüsselwert>, 'Blabla');
SELECT <autoincrementfield> FROM table WHERE f1=<Schlüsselwert>
Das dürfte innerhalb einer Transaktion in jedem DBMS funktionieren

Was ist an Stele von <autoincrementfield> denn einzusetzen, das auf jedem DBMS funktioniert?

Code:
SELECT <autoincrementfield> FROM table WHERE f1=<Schlüsselwert>
Wenn das Feld "table.f1" das Primary Key Feld ist, ergibt sich das Problem, dass man den Autonkrementwert nicht kennt, und daher logischerweise auch kein

Code:
SELECT f1 FROM table WHERE f1=<Schlüsselwert>
durchführen kann. Denn <Schlüsselwert> ist bei Autoinkrement-Feldern nicht bekannt (wenn der Wert über einen BEFORE INSERT Trigger unter Verwendung eines Firebird-Generators erzeugt wurde, hat der Client nach Ausführung des INSERT keinen Zugriff auf den soeben erzeugten <Schlüsselwert>).

supermuckl 14. Jul 2014 13:04

AW: SQL Automatisch zugeteilte Id ermitteln.
 
der TE könnte ja mal erzählen, was für eine DB er einsetzt.

//edit
da stehts :D mysql..

mkinzler 14. Jul 2014 13:05

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Man könnte auch die Frage lesen, den da steht MySQL!!

Sir Rufo 14. Jul 2014 13:09

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Die ganze Diskussion ist doch eigentlich unsinnig, denn
  1. Niemand bestreitet, dass ein RDBMS eine ID generieren kann
  2. Die Diskussion damit anfing, dass es Provider gab/gibt die es nicht schaffen diese vom RDBMS generierte ID zurück in das DataSet zu liefern.
    Beobachtetes Verhalten
    Der Datensatz war korrekt eingetragen, hatte vom RDBMS eine ID zugewiesen bekommen, aber im DataSet war dieser Datensatz immer noch mit leerem ID Feld. Um die ID zu erhalten musste das Dataset neu geladen werden und nun war das große Rätselraten, welcher Datensatz nun der war, der da gerade eingetragen wurde.
Irgendwie dreht sich der Kern dieser Diskussion darum, dass der eine meint, dass der andere meint, dass ein RDBMS keine IDs generiert, was aber niemand bezweifelt (1).

Das Thema geht eigentlich um Punkt (2) und der ist irgendwie nicht Thema der Diskussion ...

Sollte also der Provider es nicht schaffen die von MySQL (das ist das RDBMS dieses Themas) generierte ID zu liefern, dann geht man eben den folgenden Weg:
SQL-Code:
CREATE TABLE `foo` (
  `foo_id`  int NOT NULL AUTO_INCREMENT ,
  `foo_value`  varchar(50) NOT NULL ,
  PRIMARY KEY (`foo_id`) );
Delphi-Quellcode:
LQuery.SQL.Text := 'INSERT INTO foo (foo_value) VALUES (:foo_value); SELECT LAST_INSERT_ID() Foo_ID;';
LQuery.ParamByName('foo_value').Value := 'bar';
LQuery.Open;
LId := LQuery.FieldByName('Foo_ID').Value;

supermuckl 14. Jul 2014 13:12

AW: SQL Automatisch zugeteilte Id ermitteln.
 
richtig!

aber genau das

Code:
LQuery.SQL.Text := 'INSERT INTO foo (foo_value) VALUES (:foo_value); SELECT LAST_INSERT_ID() Foo_ID;';
muss in einer multiuser DB in einer transaktion aufgerufen werden, soweit ich das richtig sehe

mkinzler 14. Jul 2014 13:13

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Eher 3) Ob man davon ausgehen kann, das der Datensatzzeiger im DataSet auf dem neuen Datensatz steht

Sir Rufo 14. Jul 2014 13:18

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Zitat:

Zitat von supermuckl (Beitrag 1265476)
richtig!

aber genau das

Code:
LQuery.SQL.Text := 'INSERT INTO foo (foo_value) VALUES (:foo_value); SELECT LAST_INSERT_ID() Foo_ID;';
muss in einer multiuser DB in einer transaktion aufgerufen werden, soweit ich das richtig sehe

Nein, muss es eben nicht ...
http://dev.mysql.com/doc/refman/5.1/de/information-functions.html
  • LAST_INSERT_ID(), LAST_INSERT_ID(expr)
    Gibt den ersten automatisch erzeugten Wert zurück, der für eine AUTO_INCREMENT-Spalte durch die aktuelle INSERT- oder UPDATE-Anweisung eingestellt wurde, die eine solche Spalte modifiziert hat.
    Code:
    mysql> SELECT LAST_INSERT_ID();
            -> 195
    Die erzeugte Kennung wird auf dem Server verbindungsspezifisch gehandhabt: Der von der Funktion an einen bestimmten Client zurückgegebene Wert ist der erste AUTO_INCREMENT-Wert, der für die zuletzt abgesetzte Anweisung, die eine AUTO_INCREMENT-Spalte betraf, von diesem Client erzeugt wurde. Dieser Wert darf nicht von anderen Clients bearbeitet werden, auch wenn diese selbst AUTO_INCREMENT-Werte erzeugen. Dieses Verhalten gewährleistet, dass jeder Client seine eigene Kennung abrufen kann, ohne die Aktivitäten anderer Clients berücksichtigen oder Sperren setzen bzw. Transaktionen verwenden zu müssen.

    Der Wert von LAST_INSERT_ID() wird nicht geändert, wenn Sie die AUTO_INCREMENT-Spalte eines Datensatzes auf einen „nichtmagischen“ Wert (d. h. einen Wert, der nicht NULL und nicht 0 ist) setzen.

    Wichtig: Wenn Sie mehrere Datensätze mithilfe einer einzelnen INSERT-Anweisung einfügen, gibt LAST_INSERT_ID() nur denjenigen Wert zurück, der für den ersten eingefügten Datensatz erzeugt wurde. Grund hierfür ist, dass es möglich sein soll, dieselbe INSERT-Anweisung problemlos auf einem anderen Server zu reproduzieren.

Mikkey 14. Jul 2014 13:18

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Zitat:

Zitat von mjustin (Beitrag 1265467)
Was ist an Stele von <autoincrementfield> denn einzusetzen, das auf jedem DBMS funktioniert?

Natürlich das Feld der Tabelle, in das die erzeugte Zahl eingetragen wird.

Zitat:

Zitat von mjustin (Beitrag 1265467)
Wenn das Feld "table.f1" das Primary Key Feld ist, ...

Bitte nichts lesen, was nicht geschrieben wurde!

f1 soll nicht primary Key sein, sondern lediglich eindeutiger Schlüssel.

Sir Rufo 14. Jul 2014 13:23

AW: SQL Automatisch zugeteilte Id ermitteln.
 
Zitat:

Zitat von mkinzler (Beitrag 1265477)
Eher 3) Ob man davon ausgehen kann, das der Datensatzzeiger im DataSet auf dem neuen Datensatz steht

Nein, nach dem Post steht der Datensatzzeiger auf dem neuen Datensatz, weil er da durch das Append schon steht und durch das Post nicht weiterbewegt wird. Allerdings kann es bei einigen Providern passieren, dass diese die generierte ID dort nicht zurück liefern und eben besagte AutoIncrement-Spalte leer ist.

supermuckl 14. Jul 2014 13:48

AW: SQL Automatisch zugeteilte Id ermitteln.
 
" jeder Client seine eigene Kennung abrufen kann, ohne die Aktivitäten anderer Clients berücksichtigen oder Sperren setzen bzw. Transaktionen verwenden zu müssen."

ok das war mir neu. danke!

da arbeitet jede DB etwas anderst :)


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:16 Uhr.
Seite 1 von 2  1 2      

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