Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Interbase: Generierte ID ermitteln ? (https://www.delphipraxis.net/3907-interbase-generierte-id-ermitteln.html)

mschaefer 5. Apr 2003 12:19


Interbase: Generierte ID ermitteln ?
 
Moin, moin in die Runde

Wie kann ich an eine mit einer Trigger/Generator
angelegte ID herankommen. :?:

Möchte nach einem Post den zuletzt bearbeiteen
Datensatz noch ausgewählt haben und brauche dafür
die generierte ID...


Grüße // Martin

Gast 6. Apr 2003 22:16

Hallo MSchaefer 8)

ich werde Dir am Montag helfen... jetzt bin ich nur kurz hier...


Gruß

Paul Jr.

P.S.

Es seitdem jemand wird schneller als ich... :mrgreen:

mschaefer 7. Apr 2003 07:57

Trigger / Generator
 
Hallo Paul

bisher habe ich keine richtige Lösung gefunden. Eigenltich denke ich,
das es vermutlich über eine Stored Procedure laufen müßte, aber da
bisher kaum Erfahrung...

Grüße // Martin

Gast 7. Apr 2003 08:03

Hallo Martin 8)

Deine Vermutung ist ein Volltreffer! :idea:

So habe ich auch damals gemacht... ich muss nur etwas Suchen in meinem Durcheinander...(also gegen Nachmittag mache ich es... und ich hoffe das ich findig werde)

Gruß

Paul Jr.

Lemmy 7. Apr 2003 08:08

Hi mschaefer,

Wenn Du ID's für den Primary Key über einen Trigger in die Tabelle einträgst, hast Du immer das Problem, an diese Info ranzukommen. Dir bleibt nur der Weg für den eben eingetragenen Datensatz eine eindeutige Abfrage hinzubekommen, damit du die ID zurück bekommst. Dazu gibt es 2 Alternativen:

1. Verwende (falls Du die IBX verwendest) die Komponente TIBDataSet und dort die Eigenschaft "GeneratorField"
Falls Du über SQL eine Massenübernahme von Daten machen musst, dann kannst DU den Generator auch in die SQL einfügen:

INSERT INTO Tabelle VALUES (Gen_ID(Generatorname,1),Spalte1, SPalte2,..)

2. Hol Dir den Generator ID über ne SQL:
Select Gen_ID(Generatorname,1) AS ID from rdb§database;

die Tabelle rdb$Database existiert in jeder IB/FB DB und beinhaltet immer nur einen Datensatz.

3. Das ganze über SP machen, wobei das etwas Schreibarbeit bedeutet:

CREATE PROCEDURE InsertDATA(Wert1 Typ1, Wert2 Typ2,...)
AS
BEGIN
INSERT INTO Tabelle VALUES (Gen_ID(GeneratorName,1), Wert1, Wert2,...)
END^

Grüße
Lemmy

Gast 7. Apr 2003 08:18

Hallo Lemmy 8) ,

Dein zweiter Vorschlag mit der InterBase System Tabelle ist gut... aber nicht
100% sicher (bei Mehrbenutzer)...

Dein dritter Lösungs-Vorschlag ist der Beste :lol: ... nun... diese Storage-Procedure
sollte ein Rückgabewert haben...

Da ich lange nichts mit InterBase gemacht habe könntest Du vielleicht diese
mit einem Rückgabewert versehen...also mit dem neuem ID..., da wie ich denke
hat Martin schon etwas eilig... :coder:


Gruß

Paul Jr.

Gast 7. Apr 2003 08:24

Ich meine so was in dem Sinne:

xID = Gen_ID(GeneratorName,1) // Rückgabewert...

und erst dann INSET INTO usw... das weißt Du schon... :D


Gruß


Paul Jr.

Lemmy 7. Apr 2003 09:17

Zitat:

Zitat von Paul Jr.
HDein zweiter Vorschlag mit der InterBase System Tabelle ist gut... aber nicht
100% sicher (bei Mehrbenutzer)...

:shock: Bitte um Erklärung: Warum ist das nicht sicher???

Zitat:

Zitat von Paul Jr.
Dein dritter Lösungs-Vorschlag ist der Beste :lol: ... nun... diese Storage-Procedure
sollte ein Rückgabewert haben...

Uuups... habe ich doch glatt vergessen.... :oops:


Grüße
Lemmy

Gast 7. Apr 2003 09:23

Hallo Lemmy :D

ganz einfach... falls zwei User gleichzeitig einen neuen Datensatz anlegen (in der gleichen Tabelle)... dann steht in dem Generator nicht mehr dieses Wert die man braucht...(bei langsamen Zugriffen ist das schnell passiert)... :freak:

Gruß

Paul Jr.

Lemmy 7. Apr 2003 09:35

Zitat:

Zitat von Paul Jr.
ganz einfach... falls zwei User gleichzeitig einen neuen Datensatz anlegen (in der gleichen Tabelle)... dann steht in dem Generator nicht mehr dieses Wert die man braucht...(bei langsamen Zugriffen ist das schnell passiert)... :freak:

Halt, halt, da haben wir aneinander vorbeigeschrieben, die Schuld nehme ich auf mich! In der 2. Lösung meinte ich nicht, dass NACH dem Einfügen der Generator-Stand abgefragt werden soll (da hätte ich dann ja eigentlich ein ",0" verwende müssen) sondern, der Wert der ID soll VOR dem Einfügen über ne normale Select abgefragt werden, per "Hand" dann in das InsertSQL eingefügt werden und fertig!

Natürlich sollte man niemals NACH dem Einfügen den Generatorstand abfragen und dann Rückschlüsse auf die vom Insert verwendete Generator-ID machen!!!!

Hier noch die Insert Proc mit Rückgabewert:
Code:
SET TERM ^ ;

CREATE PROCEDURE TestNeu1 (Wert1 VARCHAR(20))
RETURNS (NewID INTEGER)
AS
BEGIN
  FOR
    SELECT Gen_ID(Generatorname,1) from rdb$database into NewID
  do
  begin
    insert into Tabelle Values (:NewID, :Wert1);
    suspend;
  end
END^
Grüße
Lemmy

Gast 7. Apr 2003 09:56

Nun... Lemmy ... ob es vorher oder nachher ist... ins hier irrelevant... denke ich... Eine SELECT Anweisung an dieser Stelle... bringt hier immer Gefahren (was wenn zwei User gleichzeitig diese Abfrage weg-schicken?)...In meinen Augen ist Deine Storage-Prozedure die richtige Lösung...

Gruß

Paul Jr.

mschaefer 7. Apr 2003 10:14

Hallo Paul, hallo Lemmy

bin wirklch begeistert ! An dem Ding beisse ich mir schon einige
Zeit die Zähne aus. Damit habt Ihr glatt die Borland-Interbase Newsgroup
in den Schatten gestellt. Die Procedure von Lemmy ist sicherlich
der eleganteste Weg. Da ich nun mit den Zeos-Komponenten auf Interbase
(genaugenommen Firebird) zugreife mag ich nochmal auf die vorweggenommene ID-Abfrage kommen.

Hiermit könnte ich im Ereignis beforePost der Query mit einer temporären
Querykomponente ein automatisch generierte SQL abschicken, die mir den Generator liefert, den ich dann ins Primarykey-Feld der Hauptquery eintragen kann. (da kann ich ja glatt noch ´ne Komponente draus basteln...)


Wenn ich das richtig verstanden habe sollte es auch kein Problem machen,
wenn zwei zur selben Zeit auf die Gerneratroabfrage zugreifen. Irgendwie wird eine zuerst bearbeitet, die Id erhöht und jeder bekommt seine Eigene. Oder hab ich was übersehen ?


Viele Grüße // Martin

Lemmy 7. Apr 2003 10:32

Zitat:

Zitat von Paul Jr.
Eine SELECT Anweisung an dieser Stelle... bringt hier immer Gefahren (was wenn zwei User gleichzeitig diese Abfrage weg-schicken?)

Nein, ganz sicher nicht!
1. Die Generatoren in IB/FB sind Transaktionsunabhängig
2. Eine Select wird immer nur in ihrer Transaktion ausgeführt!

d.h. Selbst wenn 2 User gleichzeitig diese Select ausführen, erhalten beide einen eindeutigen Generator-Wert, da dieser die Anfragen nacheinander ausführt!

Letztendlich mache ich in der SP doch genau dasselbe: Ich selektiere eine ID und verwende die anschließend in einer InsertSQL. Selbst wenn 100 User diese SP gleichzeitig ausführen kann da nix schiefgehen....

Grüße
Lemmy

Gast 7. Apr 2003 10:46

... da gebe ich mich geschlagen... 8)

Bei mir habe ich jetzt folgende Prozedur gefunden (ist eine nette Ergänzung zu unserem Thema)... wohl gemerkt die Spalte Bezeichnung ist hier NOT NULL und Eindeutig...

Code:
SET TERM ^ ;
CREATE PROCEDURE INSERT_TABLE1 (
   XBEZEICHNUNG VARCHAR(50)
) RETURNS (
   XID INTEGER
) AS
BEGIN
   xID = GEN_ID(TABLE1_ID_GEN, 1);
   INSERT INTO TABLE1 (ID
   , BEZEICHNUNG)
   VALUES(:xID
   , :xBEZEICHNUNG);
   WHEN SqlCode -803 DO
   BEGIN
      SELECT MAX(ID) FROM TABLE1
      WHERE
      (BEZEICHNUNG = :xBEZEICHNUNG)
      Into :xID;
      SUSPEND;
   END
END^

Gruß

Paul Jr.

Gast 7. Apr 2003 12:04

Hallo Martin :D ,

solltest Du Probleme haben mit Verwendung dieses Konstruktes... dann Frage ganz einfach weiter..., da es ist schon wichtig für Dich bzw. für Deine Anwendung... die Art und Weise wie Du es anbindest... bzw. wo...

Als erstes solltest Du zuerst diese Prozedur überhaupt aus Deinem Programm ansprechen... und dann überlege wie Du diese einsetzen wirst...


Gruß

Paul Jr.

Ralf Stehle 15. Okt 2004 17:55

Re: Interbase: Generierte ID ermitteln ?
 
Ich habe den Code für die Generatorabfrage ausprobiert, bin aber gescheitert

Delphi-Quellcode:
DM.IBQuery1.Active := False;
 DM.IBQuery1.SQL.Text := 'Select Gen_ID(GEN_UDAT, 1) AS ID from rdb§database';
 DM.IBQuery1.Active := true;
Ich bekomme nur die Fehlermeldung Table unknown rdb
:?:

Gruber_Hans_12345 15. Okt 2004 17:59

Re: Interbase: Generierte ID ermitteln ?
 
$, nich §


Delphi-Quellcode:
DM.IBQuery1.Active := False;
 DM.IBQuery1.SQL.Text := 'Select Gen_ID(GEN_UDAT, 1) AS ID from rdb$database';
 DM.IBQuery1.Active := true;

Ralf Stehle 15. Okt 2004 17:59

Re: Interbase: Generierte ID ermitteln ?
 
Ich hab´s. Da war ein Tippfehler bei einem Beitrag im Forum
(§ ist falsch $ ist richtig)

so muß es richtig heißen:

Delphi-Quellcode:
 DM.IBQuery1.Active := False;
 DM.IBQuery1.SQL.Text := 'Select Gen_ID(GEN_UDAT, 1) AS ID from rdb$database';
 DM.IBQuery1.Active := true;

Ralf Stehle 15. Okt 2004 18:03

Re: Interbase: Generierte ID ermitteln ?
 
wow, du warst eine sekunde schneller. Vielen Dank.
Hast Du auch eine Idee was in dieser Zeile falsch ist?

Delphi-Quellcode:
Insert Into UDAT (ID, UNTERSUCHUNGSDATUM, PATIENT) VALUES (Gen_ID(GEN_UDAT,1),''2004-10-15'',''Thomas Cook'')
Der Datensatz wird nicht eingefügt. Es kommt aber auch keine Fehlermeldung.


2. Wie kann ich einen neuen Generator per SQL-Befehl erzeugen?
Kann ich einem neuen Generator ein Nummer zuweisen, wenn ich z.B. schon Daten in einer Tabelle habe und ab sofort per Generator incrementieren möchte?

Gruber_Hans_12345 15. Okt 2004 18:09

Re: Interbase: Generierte ID ermitteln ?
 
Zitat:

Zitat von Ralf Stehle
wow, du warst eine sekunde schneller. Vielen Dank.
Hast Du auch eine Idee was in dieser Zeile falsch ist?

Delphi-Quellcode:
Insert Into UDAT (ID, UNTERSUCHUNGSDATUM, PATIENT) VALUES (Gen_ID(GEN_UDAT,1),''2004-10-15'',''Thomas Cook'')
Der Datensatz wird nicht eingefügt. Es kommt aber auch keine Fehlermeldung.


2. Wie kann ich einen neuen Generator per SQL-Befehl erzeugen?
Kann ich einem neuen Generator ein Nummer zuweisen, wenn ich z.B. schon Daten in einer Tabelle habe und ab sofort per Generator incrementieren möchte?

zu 1. Ich würde mit Parameter arbeiten, bin mir nicht sicher, wie Interbase das Datum erwartet. Wenn du per Parameter und .AsDateTime arbeitetst dann sollte es keine Probleme geben (natürlich nur wenn UNTERSUCHUNGSDATUM ein TIMESTAMP oder DATE ist !)

kannst du den ganzen Code posten (samt ExecSQL; und Transaktion ... )

2.) 'CREATE GENERATOR MEINGENERATOR;' (mit ExecSQL)
'SET GENERATOR MEINGENERATOR TO 12;'

kiar 15. Okt 2004 18:12

Re: Interbase: Generierte ID ermitteln ?
 
hallo ralf,

habe die ddl aus einer DB kopiert
SQL-Code:
CREATE GENERATOR MITID;
SET GENERATOR MITID TO 13;
versuche es.

raik

Jens Schumann 15. Okt 2004 18:21

Re: Interbase: Generierte ID ermitteln ?
 
Hallo,
ich weiss nicht ob die Frage schon beantwortet ist. Aber ich hätte auch noch eine Lösung.
Wenn in einer meiner Tabellen ein Primary-Key benötigt wird (in fast allen Tabellen ist das
der Fall) ist der Key immer in der ersten Spalte mit dem Namen "ID". Zu der Tabelle gehört
dann folgender Trigger:
Code:
CREATE TRIGGER "TRG_THEMEN_0" FOR "THEMEN"
ACTIVE BEFORE INSERT POSITION 0
as
begin
  if (new.id is null) then new.id=gen_id(gen_themen,1);
end
Wenn bei einem INSERT das FELD ID nicht angegeben wird holt sich der Trigger einen
neuen Generatorwert. Wenn ID einen Wert hat, wird eben kein neuer Generatorwert geholt.

Wenn ich vor dem INSERT den Wert für ID brauche hole ich mir diesen
über folgende StoredProc
Code:
CREATE PROCEDURE "GET_THEMENID"
RETURNS
(
  "NEWID" INTEGER
)
AS
BEGIN NewID = GEN_ID(GEN_THEMENID,1);
END ^

Robert_G 15. Okt 2004 18:57

Re: Interbase: Generierte ID ermitteln ?
 
Ich wollte mich dieses WE mal mit FB beschäftigen, da ich für ein kleineres Projekt(, dass in naher Zukunft anläuft) eine passende kleine, günstige DB suche.
Deshalb mal meine Frage: Gibt es keinen konsistenten Weg um den PK eines neuen DS zu bekommen?
Ich meine im Normalfall würde ein Standardtrigger von mir, zu PSQL übersetzt, so aussehen (keine Gewähr, ich habe keinen Plan von PSQL :stupid: ):
SQL-Code:
CREATE TRIGGER SomeTable$PKtrig FOR SomeTable
ACTIVE BEFORE INSERT OR UPDATE POSITION 0
AS
begin
  if (INSERTING) then
    NEW.PK = GEN_ID(SomeTable$PKseq, 1);
  if (UPDATING) then
    NEW.PK = OLD.PK;
end
Es wird also _IMMER_ der PK aud der Sequence genommen und _KEINE_ Änderung des PK ermöglicht.
Die Frage ist jetzt nur: Wie zum Geier würde ich an die PK nach einem INSERT bekommen?
Das gibt's ja in FB/IB nicht:
SQL-Code:
INSERT INTO SomeTable
 (A, B, C)
VALUES
 (:iA, :iB, :iC)
RETURNING PK INTO :oPK
Alle anderen Vorschläge würden doch bewirken, dass jeder, der an dem Projekt arbeitet, _IMMER_ erst den PK aus der _RICHTIGEN_ Sequence holen muss. (Eine schöne Gelegenheit für einen unnötigen Bug. ;) )

Wie sieht es mit FB 2.0 aus, wurde dort schon eine Lösung für das Problem gefunden?

Ralf Stehle 15. Okt 2004 20:15

Re: Interbase: Generierte ID ermitteln ?
 
Ich kapiere das mit Generator und Trigger nicht.

Ich habe in IBExpert einen Generator Gen_UDat eingegeben, das hat scheinbar geklappt.
Danach habe ich bei Trigger folgende Anweisung gemacht

SQL-Code:
INSERT TRIGGER UDAT_BI0
ACTIVE BEFORE INSERT POSITION 0
AS
begin
  if (new.id is null) then new.id=gen_id(gen_udat,1);
end
Müsste jetzt nicht automatisch das Feld ID hochgezählt werden ?
Bei Einfügen kommt aber leider immer noch die Fehlermeldung, ID darf nicht Null sein

kiar 15. Okt 2004 20:21

Re: Interbase: Generierte ID ermitteln ?
 
das ist so nicht richtig.

womit erzeugst du den trigger? IBConsole, Ibexpert oder von hand?

Ralf Stehle 15. Okt 2004 20:30

Re: Interbase: Generierte ID ermitteln ?
 
Stimmt. In IBExpert kommt eine Fehlermeldung. Wie muss es denn richtig heißen?
Kann man das auch aus einer Delphi-Anwendung heraus machen

Ralf Stehle 15. Okt 2004 20:40

Re: Interbase: Generierte ID ermitteln ?
 
Dumme Frage:

was bedeuten in oben geposteten Beitrag

Delphi-Quellcode:
INSERT INTO SomeTable
(A, B, C)
VALUES
(:iA, :iB, :iC)
RETURNING PK INTO :oPK
der Doppelpunkt?

Robert_G 15. Okt 2004 20:57

Re: Interbase: Generierte ID ermitteln ?
 
Na du bist mir ja ein DB'ler.. ;)
Das ist ein [dp:b229d9c4b0=SQL AND Parameter]SQL Parameter[/dp:b229d9c4b0].

Ralf Stehle 15. Okt 2004 21:09

Re: Interbase: Generierte ID ermitteln ?
 
Danke für Dein Verständnis. Während meines "Learning bei Doing" habe ich noch nichts mit Parametern zu tun gehabt. Falls Du hierfür ein TUTO weißt, bin ich Dir dankbar, Dein Verweis auf das Forum hat aber auch schon mehr als genug Beiträge zu dem Thema angezeigt

CenBells 16. Okt 2004 09:39

Re: Interbase: Generierte ID ermitteln ?
 
Zitat:

Zitat von Ralf Stehle
Ich kapiere das mit Generator und Trigger nicht.

Ich habe in IBExpert einen Generator Gen_UDat eingegeben, das hat scheinbar geklappt.
Danach habe ich bei Trigger folgende Anweisung gemacht

SQL-Code:
INSERT TRIGGER UDAT_BI0
ACTIVE BEFORE INSERT POSITION 0
AS
begin
  if (new.id is null) then new.id=gen_id(gen_udat,1);
end
Müsste jetzt nicht automatisch das Feld ID hochgezählt werden ?
Bei Einfügen kommt aber leider immer noch die Fehlermeldung, ID darf nicht Null sein

Hi,
der trigger ist nicht richtig definiert.
Das muß so heißen
SQL-Code:
CREATE TRIGGER DeinTriggerName FOR DeineTabelle
ACTIVE BEFORE INSERT POSITION 0
AS
begin
  if (new.id is null) then new.id=gen_id(gen_udat,1);
end
Und ja, du kannst ihn auch aus Delphi heraus erzeugen. Dazu benötigst du die Komponente IBScript aus dem neuesten IBXpress Update (oder was vergleichbares).

Gruß
ken

edit: sql-skript ausgebessert Crate -> Create


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:07 Uhr.

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