Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Firebird : Tabelle erstellen mit AutoInc-Feld (https://www.delphipraxis.net/92697-firebird-tabelle-erstellen-mit-autoinc-feld.html)

RWarnecke 24. Mai 2007 16:26


Firebird : Tabelle erstellen mit AutoInc-Feld
 
Hallo zusammen,

ich erstelle mit folgenden Script eine Tabelle :

SQL-Code:
CREATE TABLE PRODUKTE (
    ID INTEGER NOT NULL,
    PRODUCTID VARCHAR(100) NOT NULL,
    BEZEICHNUNG VARCHAR(255) NOT NULL);
CREATE GENERATOR GEN_PRODUKTE_ID;
SET TERM ^ ;

create trigger produkte_bi for produkte
active before insert position 0
as
begin
  if (new.id is null) then
    new.id = gen_id(gen_produkte_id,1);
end
^

SET TERM ; ^

SET TERM ^ ;

create procedure sp_gen_produkte_id
returns (id integer)
as
begin
  id = gen_id(gen_produkte_id, 1);
  suspend;
end
^

SET TERM ; ^
So wie muss ich jetzt den Insert-Befehl schreiben, damit das Feld ID mit dem AutoIncrementwert gefüllt wird ?

DeddyH 24. Mai 2007 16:30

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
Hallo,

wozu dient denn die SP? Na, egal, so sollte es gehen:
SQL-Code:
INSERT INTO Produkte(ProductId, Bezeichnung) VALUES('12345','Ein Produkt')

RWarnecke 24. Mai 2007 16:42

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
Danke, wunderbar hat funktioniert.

DP-Maintenance 24. Mai 2007 17:52

DP-Maintenance
 
Dieses Thema wurde von "Phoenix" von "Programmieren allgemein" nach "Datenbanken" verschoben.
Das war ne Datenbank-Frage

Elvis 24. Mai 2007 20:49

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
Du solltest im Trigger bedingungslos die ID aus dem Generator eintragen.
Warum?
Es könnte sonst es zu Schlüsselverletzungen führen:
Der Generator steht bei 3, aber User trägt selbst 3 ein.
Beim nächsten Insert ohne dass der User eine Id angibt würde der Generator um eins erhöht und versucht eine weitere 3 einzufügen -> Kabumm

Wie kriegst du die Id nach einem Insert?
Bei einem Insert führst du das hier mit Query.Open aus (nicht ExecSql!):
SQL-Code:
INSERT INTO Produkte
  (ProductID
  ,Bezeichnung)
VALUES
  (:ProductID
  ,:Bezeichnung)
RETURNING Id
In der "Ergebnismenge" findest du die neue ID in der ersten Spalte.

DeddyH 24. Mai 2007 21:02

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
Das Dumme ist, dass ich diesen Trigger auch schon in einer Doku gesehen habe (ob das jetzt auf firebirdsql.org oder ibphoenix.com oder sonstwo war, weiß ich leider nicht mehr). Ich stimme Dir zu, wenn schon "Auto_inc", dann richtig.

Elvis 24. Mai 2007 21:07

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
Zitat:

Zitat von DeddyH
Das Dumme ist, dass ich diesen Trigger auch schon in einer Doku gesehen habe

Vor Firebird 2.0 war kein konsistentes Handling von generator-basierten Pks möglich.
Erst die neue Returning-Clause erlaubt es.

Zitat:

Ich stimme Dir zu, wenn schon "Auto_inc", dann richtig.
Schreibe bitte nicht auto_inc. Das erinnert mich an andere DBMS, die sowas haben, aber keine Sequences/Generatoren: Praktisch Access für den Server. :kotz:

DeddyH 24. Mai 2007 21:10

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
Naja, zum Einen hatte ich diesen Begriff mit Absicht in Anführungszeichen gesetzt und zum Anderen bezog ich mich dabei auf den Titel dieses Threads :) .
Schönen Abend noch

RWarnecke 24. Mai 2007 21:55

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
Wie funktioniert denn ein richtiger AutoInc von der SQL-Syntax bei Firebird ?

mkinzler 24. Mai 2007 22:05

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
Zitat:

Wie funktioniert denn ein richtiger AutoInc von der SQL-Syntax bei Firebird ?
Er meinte nur das das Generator/Sequenz-Konzept flexibler ist als autoinc von MySQL, Access und Konsorten

Hansa 24. Mai 2007 22:10

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
Das steht in Deinem ersten Beitrag, sofern man die überflüssige SP weg lässt. Mehr ist es nicht. Es gilt allerdings, die ID nicht selber einzutragen. Das muss dann schon der Trigger machen, damit auch die MGA greift.

RWarnecke 24. Mai 2007 22:18

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
Ich hätte noch 2 Fragen noch dazu :
1.) Verstehe ich das richtig, wenn ich diesen Teil weglasse
SQL-Code:
SET TERM ^ ;

create procedure sp_gen_produkte_id
returns (id integer)
as
begin
  id = gen_id(gen_produkte_id, 1);
  suspend;
end
^

SET TERM ; ^
Dann kann ich dem Problem aus dem Weg gehen, welches Elvis angesprochen hat ?

2.) Und was ist zum Teufel eine Multi-Generationen-Architektur (MGA) ?

Hansa 24. Mai 2007 22:25

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
Ja, wegen der MGA sollte gar kein Problem entstehen. Die SP ist ein Ersatz für einen vor FB 2.0 nicht vorhandenen Trigger, der auch Rückgabewerte liefert. Werden die überhaupt gebraucht ? Im Normalfall überlässt man die IDs der DB und basta.

mkinzler 24. Mai 2007 22:28

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
Der Trigger liefert immer noch keinen Rückgabewert, sondern das Insert-Statement. Man kann aber die ID auch vom Client setzen, solange man den Generator verwendet

Hansa 24. Mai 2007 23:39

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
Zitat:

Zitat von mkinzler
Der Trigger liefert immer noch keinen Rückgabewert..

So, wie er da steht sichelich nicht. Wird der jetzt dringend gebraucht oder doch nicht ? Bevor dies nicht geklärt ist, lohnt keine Diskussion.

mkinzler 25. Mai 2007 07:42

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
Zitat:

So, wie er da steht sichelich nicht
Ein Trigger liefert nie ienen Rückgabewert an den Client, weil er ja nicht von ihm aufgerufen wird.

alex517 25. Mai 2007 08:43

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
Hi,

Zitat:

Zitat von Elvis
Vor Firebird 2.0 war kein konsistentes Handling von generator-basierten Pks möglich.
Erst die neue Returning-Clause erlaubt es.

Das ist nicht richtig!

Ich habe generell folgende Vorgehensweise:

1. Alle Tabellen haben ein PK-Feld "ID".

2. Diese ID wird ggf. durch einen Trigger, wie RWarnecke ihn schon verwendet, gesetzt
SQL-Code:
create trigger produkte_bi for produkte
active before insert position 0
as
begin
  if (new.id is null) then
    new.id = gen_id(GEN_PRODUKTE_ID,1);
end
3. Wenn es das Programm noch vor dem Absetzen eines Statements eine neue ID erfordert, z.B. für ein Insert
bei Master-Detail Verknüpfungen, so wird diese neue ID vorher explizit durch das Programm geholt.
Das kann mittels der verwendeten Komponenten (bei mir FIBPlus) erfolgen oder
über eine eigene Query mit folgendem Statement (FIBPlus macht auch nichts anderes):
SQL-Code:
select GEN_ID(GEN_PRODUKTE_ID, 1) from RDB$DATABASE
Ich brauche also keine extra SP und ein "konsistentes Handling von generator-basierten Pks"
ist auch auch vor FB 2.0 gewährleistet.

Unter FB2.x kann Rückgabe der ID wie Elvis schrieb mit "INSERT .. RETURNING ID" verfolgen.
Damit entfällt der Punkt 3.
Den Trigger würde ich aber immer beibehalten.


alex

Elvis 25. Mai 2007 17:41

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
Zitat:

Zitat von alex517
Zitat:

Zitat von Elvis
Vor Firebird 2.0 war kein konsistentes Handling von generator-basierten Pks möglich.
Erst die neue Returning-Clause erlaubt es.

Das ist nicht richtig!

Nicht zu schnell widersprechen! :warn: ( ;) )
Zitat:

Ich habe generell folgende Vorgehensweise:...
Die hattest nicht nur du, die hatte jeder andere auch, der die ID des neuen Datensatzes in der dunklen Pre-FB2.0-Ära brauchte.
Zitat:

Ich brauche also keine extra SP und ein "konsistentes Handling von generator-basierten Pks"
ist auch auch vor FB 2.0 gewährleistet.
Und ich hoffe, dass du in der Doku deiner Software hinterlegt hast, dass niemand einen Wert für die ID angibt, außer er hat ihn vorher zu Fuss aus dem Generator geholt.
Ansonsten schreibt einer eine 1000 rein und irgendwann, 3 Wochen später, will dein Programm über den friemeligen "Generator abfragen & Wert beim Insert mitgeben"-Weg einen Datensatz einfügen und es knallt! Nun, irgendwann musste der Generator ja die 1000 erreichen. :mrgreen:
Zitat:

Unter FB2.x kann Rückgabe der ID wie Elvis schrieb mit "INSERT .. RETURNING ID" verfolgen.
Damit entfällt der Punkt 3.
Den Trigger würde ich aber immer beibehalten.
Natürlich braucht man den Trigger, er sollte die ID aber bedingungslos aus dem Generator setzen, auch wenn beim Insert schon ein Wert dafür angegeben wurde.

Hatte ich das wirklich so unverständlich geschrieben? :gruebel:

Hansa 25. Mai 2007 20:01

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
Zitat:

Zitat von Elvis
...der die ID des neuen Datensatzes in der dunklen Pre-FB2.0-Ära brauchte...

in dieser "dunklen Ära" hat man eben eine SP benutzt, um direkt nach dem Einfügen eines Datensatzes die ID zu erhalten. Ein Trigger ist nichts anderes, als eine spezielle SP.

alex517 26. Mai 2007 12:31

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
Zitat:

Zitat von Elvis
Nicht zu schnell widersprechen! :warn: ( ;) )

:warn: Oh, doch! :wink:
Zitat:

Zitat von Elvis
Und ich hoffe, dass du in der Doku deiner Software hinterlegt hast, dass niemand einen Wert für die ID angibt, außer er hat ihn vorher zu Fuss aus dem Generator geholt.
Ansonsten schreibt einer eine 1000 rein und irgendwann, 3 Wochen später, will dein Programm über den friemeligen "Generator abfragen & Wert beim Insert mitgeben"-Weg einen Datensatz einfügen und es knallt! Nun, irgendwann musste der Generator ja die 1000 erreichen. :mrgreen:

Das Holen der ID über
SQL-Code:
select GEN_ID(GEN_..._ID, 1) from rdb$database
erfolgt durch das Programm direkt vor dem Absetzen des Insert-Statements und ist in keinem Fall dem Benutzer überlassen.
Da die neue ID durch den selben Generator erzeugt wird, der auch im Trigger Verwendung findet, kann es niemals vorkommen, dass die IDs doppelt vergeben werden.
Der Vorgang der ID-Vergabe ist also in beiden Fällen (Trigger/select GEN_ID(..)) identisch, er wird nur falls notwendig in das Programm vorverlegt.

Zitat:

Zitat von Elvis
Natürlich braucht man den Trigger, er sollte die ID aber bedingungslos aus dem Generator setzen, auch wenn beim Insert schon ein Wert dafür angegeben wurde.

Dazu folgendes Szenario:
Ich generiere eine NEUE Rechnung (Rech) mit Rechnungsposten (RPosten) im Formular.
Da Rech- und RPosten-Daten in einer Transaktion gespeichert werden müssen, benötige ich vorher die ID der Rechnung, um diese
in den RPosten-Daten als Link(FK) auf die Rech eintragen zu können. Ich hole mir, wie oben beschrieben, explizit eine neu ID, und gebe diese beim Insert sowohl der Rechnung als auch den RPosten mit.
Fertig!
Äh.., natürlich nur wenn der Trigger nicht einfach bedingungslos der Rechnung eine andere ID verpasst.
Aber den Trigger habe ja ich angelegt und nicht Elvis :wink:

Zitat:

Zitat von Elvis
Hatte ich das wirklich so unverständlich geschrieben? :gruebel:

Nein, nicht unverständlich, aber ich denke, dass ich Recht habe.

Es ist also keine dunkle Ära, man muss nur die Augen aufmachen, damit es hell wird! :mrgreen:

Schöne Pfingsten
alex

:cheers:

mkinzler 26. Mai 2007 12:41

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
IMHO sind alle Lösungen, welche auf Generatoren aufsetzen gleich gut. Seien es jetzt durch Einsatz eines Triggers, einer SP, direkt im Statement oder dem Einsatz von clientseitiger Komponenten, welche darauf aufsetzen (TZSequence usw.)

Elvis 26. Mai 2007 13:49

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
Zitat:

Zitat von alex517
Zitat:

Zitat von Elvis
Nicht zu schnell widersprechen! :warn: ( ;) )

:warn: Oh, doch! :wink:

Gibst nicht auf was? :)

Zitat:

Zitat von alex517
Zitat:

Zitat von Elvis
Natürlich braucht man den Trigger, er sollte die ID aber bedingungslos aus dem Generator setzen, auch wenn beim Insert schon ein Wert dafür angegeben wurde.

Dazu folgendes Szenario:
Ich generiere eine NEUE Rechnung (Rech) mit Rechnungsposten (RPosten) im Formular.
Da Rech- und RPosten-Daten in einer Transaktion gespeichert werden müssen, benötige ich vorher die ID der Rechnung, um diese
in den RPosten-Daten als Link(FK) auf die Rech eintragen zu können. Ich hole mir, wie oben beschrieben, explizit eine neu ID, und gebe diese beim Insert sowohl der Rechnung als auch den RPosten mit.
Fertig!

Also die Rechungsposten haben einen FK auf die Rechung? Das heißt die Rechung muss existieren bevor du den Rechnungsposten einfügen kannst? Wenn du jetzt mit Ja/Ja antwortest, dann war das kein Grund diese potentielle Schlüsselverletzung im Trigger zu lassen. ;)
Pseudo code:
Delphi-Quellcode:
using transaction := deineConnection.BeginTransaction() do
begin
  using command := connection.CreateCommand() do
  begin
    command.CommandText := 'INSERT INTO Rechungen(blabla) VALUES(:Blabla) RETURINNG ID';
    command.Parameters.Add('Blabla', 1);
    var rechungsId := command.ExecuteScalar() as Integer;
    command.CommandText := 'INSERT INTO RechungsPostenen(Rechung) VALUES(:Rechung) RETURNING ID';
    command.Parameters.Add('Rechung', rechungsId);
    var rechungsPostenId := command.ExecuteScalar() as Integer;
    ...
  end;
 
  transaction.Commit();
end;
Zitat:

Äh.., natürlich nur wenn der Trigger nicht einfach bedingungslos der Rechnung eine andere ID verpasst.
Aber den Trigger habe ja ich angelegt und nicht Elvis :wink:
;-)

Zitat:

Zitat:

Zitat von Elvis
Hatte ich das wirklich so unverständlich geschrieben? :gruebel:

Nein, nicht unverständlich, aber ich denke, dass ich Recht habe.
Kann gar nicht sein.... :mrgreen:
Zitat:

Es ist also keine dunkle Ära, man muss nur die Augen aufmachen, damit es hell wird! :mrgreen:
Ganz genau! :P


Zitat:

Zitat von mkinzler
IMHO sind alle Lösungen, welche auf Generatoren aufsetzen gleich gut. Seien es jetzt durch Einsatz eines Triggers, einer SP, direkt im Statement oder dem Einsatz von clientseitiger Komponenten, welche darauf aufsetzen (TZSequence usw.)

Wenn ich 2 Lösungen für ein Problem habe, und die eine mindestens ein weiteres Problem bewirken kann, ohne Vorteile zu bringen...
Dann können nicht beide Lösungen gleich gut sein. ;)

Hansa 26. Mai 2007 14:31

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
Zitat:

Zitat von Elvis
Wenn ich 2 Lösungen für ein Problem habe, und die eine mindestens ein weiteres Problem bewirken kann, ohne Vorteile zu bringen...
Dann können nicht beide Lösungen gleich gut sein. ;)

Du hast dabei vergessen : viele Wege führen nach Rom. Und dann noch, dass Alex sowieso Recht hat. :mrgreen:

Er hat das klassische Bsp. der Rechnung erklärt. Genau so nuss es gemacht werden. Also wird Rückgabewert gebraucht. Der Trigger scheidet somit aus und die beiden Möglichkeiten bestehen dann darin eine SP zu verwenden oder eben FB 2.0. Beides ist für den Zweck gut und macht keine Probleme.

Elvis 26. Mai 2007 14:48

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
Sorry Alex, "schöne Pfingsten" vergessen.


Und nun die quartalsmäßige Antwort an Hansa:
Zitat:

Zitat von Hansa
Er hat das klassische Bsp. der Rechnung erklärt. Genau so nuss es gemacht werden. Also wird Rückgabewert gebraucht. Der Trigger scheidet somit aus...

Warum kannst du dir nicht einfach angewöhnen nicht auf meine Beiträge zu antworten? Du hast natürlich wieder absolut gar nix kapiert, in dem Fall dass das erste Insert direkt die Rechnungs-ID zurückgegeben hat.
Deine "Kompetenz" beginnt und endet bei Firebird, und selbst da hast du absolut keinen Plan.

Kleiner Tipp an alle anderen, wenn es euch so wie mir gerade geht[1], versucht das was ich normalerweise auch mache: Versucht ihn zu ignoriert...


[1] Hansa hat auf einen Beitrag von euch geantwortet

alex517 29. Mai 2007 20:18

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
Zitat:

Zitat von Elvis
Also die Rechungsposten haben einen FK auf die Rechung? Das heißt die Rechung muss existieren bevor du den Rechnungsposten einfügen kannst? Wenn du jetzt mit Ja/Ja antwortest, dann war das kein Grund diese potentielle Schlüsselverletzung im Trigger zu lassen. ;)

Ich verstehe nicht so richtig was du damit sagen möchtest. :gruebel:
Aber ich werte ich das einfach als Zustimmung zu meiner Darstellung. Überredet? ;)


alex

Elvis 30. Mai 2007 09:46

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
Zitat:

Zitat von alex517
Ich verstehe nicht so richtig was du damit sagen möchtest. :gruebel:

Was da steht. :mrgreen:
IOW, dein Einwand für das manuelle Generatorgefriemel und die Lücke im Trigger, die es ermöglicht eine ID in die Tabelle einzufügen, die als DeinGenerator.NextValue ist.
Ich wollte zeigen dass es mit "Returning" auch in dem von dir geschilderten Fall einfacher ist. Wenn zusätzlich die Lücke aus dem Trigger entfernt werden kann ist's ja nur besser. :)
Schließlich kannst du ja nur dann einen FK von Rechnungsposten auf Rechungen haben wenn der Rechungsdatensatz existiert, bevor du den Rechungsposten einfügst.
Zitat:

Aber ich werte ich das einfach als Zustimmung zu meiner Darstellung. Überredet? ;)
Tsss.... Dickkopf.... :mrgreen:

alex517 30. Mai 2007 10:42

Re: Firebird : Tabelle erstellen mit AutoInc-Feld
 
Zitat:

Zitat von Elvis
Ich wollte zeigen dass es mit "Returning" auch in dem von dir geschilderten Fall einfacher ist.

Ja, sofern bereits FB2.x verwendet wird.

Zitat:

Zitat von Elvis
Wenn zusätzlich die Lücke aus dem Trigger entfernt werden kann ist's ja nur besser.

Jetzt verstehe ich erst, was du mit "Lücke im Trigger" meinst.
Diese Lücke ist aber nur theoretisch, da praktisch das Programm die ID vor dem Insert aus dem Generator holt.


Allerdings bekommst du mit deinem "lückenslosen"-Trigger u.U. Probleme:
z.B beim Import bestehender verlinkter Daten, der Trigger muß dann ggf. deaktiviert werden.


von
Zitat:

Tsss.... Dickkopf.... :mrgreen:
So bin ich.. :-D

alex


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:37 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 by Thomas Breitkreuz