![]() |
Datenbank: Firebird • Version: 1.5 • Zugriff über: Zeos 6.5.1
Autowerte bei Firebird setzen
Hallo,
ich bastel gerade an einem Programm, dass über die Zeos-Komponenten auf einen Firebird-Server zugreift. Nun habe eine Tabelle in meiner FB-Datenbank, die über ein Feld "ID" verfügt. Dieses Feld ist primärer Index und als "autoinc" definiert. Wenn ich nun einen Datensatz speichern will (über den Navigator), erhalte ich die Fehlermeldung, dass der Insert-Befehl gescheitert wäre. Wenn ich dann über ein DBEdit-Feld einen Wert für ID eintrage, klappt der Insert. Dabei sollte doch ein Autowert automatisch gesetzt werden, oder? Für das Feld ID hat IBExpert noch einen Generator angelegt, der wohl für diese AutoInc-Sachen zuständig ist. Muss ich den irgendwie anstoßen/ausführen? Wenn ja, wie? Gruß Frank |
Re: Autowerte bei Firebird setzen
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Schau mal nach, ob es bei den Zeos auch so was gibt. André |
Re: Autowerte bei Firebird setzen
Hallo André,
hab nachgesehen, es gibt für das einzelne Feld über den Feldeditor der ZTable-Komponente die Eigenschaft "AutoGenerateValue", aber wenn ich die auf "arAutoInc" setze, erhalte ich trotzdem die gleiche Fehlermeldung. Gruß Frank |
Re: Autowerte bei Firebird setzen
Als ich das letzte mal mit Firebird gearbeitet habe (war gerade die 1.0 frisch raus) gabe es sowas wie ein "autoinc" Flag garnicht. Stattdessen musste man sich ein Konstrukt aus einem Trigger und einer Sequenz basteln wobei die Sequenz die ID hochzählt und der Trigger diese einfügt.
Daher meine Frage: Wie hast Du das Feld als autoincrement definiert? Falls die 1.5 Firebird o.g. Konstrukt nicht mehr benötigt vergiss alles was ich gesagt habe :) Bis neulich ... |
Re: Autowerte bei Firebird setzen
Hallo Grendel,
ich hab die Datenbank und die Tabellen mit IBExpert erzeugt. Dort kann man in dem Dialog zur Tabellengenerierung "autoinc" ankreuzen. Aufgrund dieser Angabe erzeugt IBExpert dann einen sog. Generator mit einem definierten Startwert. Allerdings weiss ich nicht, ob ich den Generator extra ansprechen muss, da ja z. B. beim ADS oder bei der BDE Autoinc-Felder automatisch hochgezählt werden, hier passiert allerdings nix. Natürlich kann ich mir mit "SELECT MAX..." den höchsten Wert aus der Tabelle holen und um 1 erhöhen, aber dann bräuchte ich kein Autoinc.... Gruß Frank |
Re: Autowerte bei Firebird setzen
Hallo,
dann erzeuge doch einfach noch den passenden Trigger dazu und du brauchst dich um die Erstellung nicht mehr zu kümmern, da die DB das für dich erledigt.
SQL-Code:
AS
BEGIN IF (NEW.ID IS NULL) THEN NEW.ID = GEN_ID(DB_Name_ID_GEN, 1); END |
Re: Autowerte bei Firebird setzen
Hallo Albi,
ist ja schön und gut, aber wozu brauche ich dann die "AutoInc"-Definition? Und wie nutze ich die? Gruß Frank |
Re: Autowerte bei Firebird setzen
Hallo Frank,
eine Möglichkeit zur "automatischen" Vergabe von ID für deine Tabelle TBL unter Verwendung eines Generators ist ein Trigger, wie er im Handbuch steht. Ich gehe davon aus, dass der Generator so heißt wie die Tabelle.
SQL-Code:
Ich habe immer einen solchen Trigger - und benutze ihn dann nicht. Der Trigger dient bei mir nur der Unterstützung von bulk-load Operationen. Den ID für single record inserts hole ich mir vom Generator und setze ihn in der Anwendung. Auf diese Weise habe ich die ID für meinen Programm-Kontext. Echte AutoInc-Felder machen bei primary key Feldern mehr Probleme als Freude.
CREATE TRIGGER "TBL_BI0" FOR "TBL"
ACTIVE BEFORE INSERT POSITION 0 as begin if (new.id = 0) then new.id = gen_id(TBL, 1); end Grüße vom marabu |
Re: Autowerte bei Firebird setzen
Hallo,
Du sagst damit nichts weiter wie das ein Generator erzeugt wird. Diesen kannst Du entweder selber in der StoredProcedure machen über
SQL-Code:
Oder Du erzeugst noch den passenden Trigger, dann kannst Du dir in der SP eben das Feld ID sparen. Und die DB kümmert sich um die Vergabe der DB.
...
... Insert Into DB (ID,...,...) Values (gen_ID(DB,1),...,...) Welche Vorteile oder Nachteil das hat, kann ich dir auch nicht sagen. Aber ich bevorzuge immer die Variante mit den Trigger (wahrscheinlich aus Bequemlichkeit :-D ) |
Re: Autowerte bei Firebird setzen
Hallo,
ich habe mittlerweile einen möglichen Grund gefunden. Wenn man im IBExpert eine Tabelle anlegt, kann man auch ein Feld als AutoInc definieren. IBExpert erzeugt dann einen Generator und verknüpft ihn dann mit dem Feld. Allerdings scheint IBExpert die Verbindung nicht in der Datenbank zu speichern, da beim Bearbeiten der Tabelle die entsprechende Checkbox leer ist. Weist man nun erneut den bereits definierten Generator zu und speichert ab, so ist bei erneutem Öffnen der Feldeigenschaften die Checkbox wieder leer (nicht gesetzt). Also werd ich wohl einen Trigger einbauen, der beim Insert das Feld ID um eins erhöht. Danke für Eure Antworten. Gruß Frank |
Re: Autowerte bei Firebird setzen
Hallo,
dann schaue Dir mal die Feldbeschreibung an. Da wirst Du sehen, dass der Primary Key gesetzt wurde, sich die Datenbank also die Einstellung gemerkt hat. Wenn Du beim anlegen der DB halt AutoInc auswählst, ist das wohl das gleiche wie der Primary Key. Also ein eindeutiger Schlüssel, der nur einmal vorkommt. Ob Du nun diesen Schlüssel selber erstellst oder über einen Trigger dies machen lässt, bleibt im Grunde dir überlassen. Ich habe habe das Feld AutoInc im IBExpert nur gesehen, wenn du die Table bzw. das Feld anlegst, danach ist es wie schon gesagt nur über die Feldeigenschaften zu erkennen, in welchem Verhältnis was zu wem steht. Hast Du das Feld vielleicht mit dem "Not Null" verwechselt? |
Re: Autowerte bei Firebird setzen
Zitat:
Seitdem muss man tatsächlich so vorgehen, wie du es beschrieben hast. In Ora mache ich es meist so:
Delphi-Quellcode:
Die ID bekomme ich so:
create or replace trigger X_PkTrig
before INSERT or UPDATE ON SomeSchema.X -- rename New and Old, they could be used as table or column names ... REFERENCING New AS New$Rec Old AS Old$Rec for each row begin if Inserting then -- get next value from sequence SELECT SomeSchema.X_PkSeq.NextVal INTO :New$Rec.ID FROM dual; elsIf Updating then -- prevent changes of ID :New$Rec.ID := :Old$Rec.ID; end if; end SomeSchema.X_PkTrig;
SQL-Code:
Wenn man die Cache size der sequence passend wählt macht es sich auch in großen bulk inserts nicht wirklich bemerkbar. ;)
insert into X (a,b) values (:a,:b) returning id into :id;
Das schöne an der Methode ist, dass ich sie komplett automatisch ablaufen lassen kann. (Also die Erzeugung von Trigger/Sequence) :) btw: Seit wann kann FB Bulk DML? :gruebel: |
Re: Autowerte bei Firebird setzen
Hallo Albi,
Zitat:
Nun, wie gesagt, ich bau dann eben einen Trigger ein. Gruß Frank |
Re: Autowerte bei Firebird setzen
Moin, Spätmoin
Zitat:
Grüße // Martin |
Re: Autowerte bei Firebird setzen
Zitat:
Verpasse ihm eine Eigenschaft mit dem Generatornamen, überschreibe OnBeforePost und gut ist. ;) |
Re: Autowerte bei Firebird setzen
Tach Robert,
ja - genausowas habe ich dann auch gemacht (muß ja nicht gleich mit der Tür ins Haus fallen), aber leider muß ich jetzt immernoch bei jedem Dataset den SQL-Befehl für das holen des Trickers extra eintragen. Im Moment habe ich eine zusätzliche StringListe mit der Generator-Abfrage die im BeforePost über ein temporäres Dataset abläuft... Mir ist es also nich gelungen, daß so zu verallgemeinern, daß man einfach eine Eigenschaft GetGeneratorrBeforePost auf True setzt und gut. Das ist leider nervig. Grüße // Martin |
Re: Autowerte bei Firebird setzen
Ich hoffte, dass vielleicht noch ein paar mehr Infos kommen würden...
Ehrlich gesagt hoffe ich, dass ich das falsch verstanden habe. ;) Zitat:
Zitat:
|
Re: Autowerte bei Firebird setzen
Zitat:
|
Re: Autowerte bei Firebird setzen
Zitat:
Nur weil DU es nicht kapierst musst du nicht alle anderen als Vollidioten abstempeln. :roll: Zitat:
Zitat:
Wie man eindeutig zwischen den Zeilen herauslesen kann, steht mir deine arrogante Art, anderen deine Unwissenheit bekannt zu tun, mal wieder bis Oberkante Unterlippe. Wenn du in dem Thread weiter rumpupst vergeht mir ziemlich schnell die Lust daran. Ich glaube aber, dass das schade wäre. Denn man könnte hier sicherlich einige stupide Codezeilen und Nerven einsparen. ;) |
Re: Autowerte bei Firebird setzen
Zitat:
|
Re: Autowerte bei Firebird setzen
Hallo ihr,
ich will euch mal bitten, sachlich zu bleiben. So eine "Diskussion" bringt wirklich keinem was. Auch wenn ich die Materie nicht wirklich verstehe (:oops: ich bin eben kein Datenbankmensch), aber ich denke der Vorschlag von Robert hat durchaus was sinnvolles, was nicht durch irgendwelche Kommentare "dummgeredet" werden muss. @Hansa: tut mir Leid wenn ich dich direkt anspreche, aber du bist nicht der, der versucht hat das Problem zu loesen. Ich bitte dich also, die unnuetzen Kommentare fuer dich zu behalten, oder diesen Disput mit Robert per PN auszutragen. Das was hier abgeht hilft dem Threadersteller beim besten Willen nicht, und auch wenn es fuer den einen nur "Woerter, die verwirren" sind, fuer den anderen kann so ein Loesungsweg durchaus Sinn ergeben. Und um auf den Kommentar des "Oberschlaumeiers" einzugehn: nur weil jemand versucht zu helfen, und dabei auch ziemlich komplizierte Loesungsvorschlaege kommen, muss man jemanden nicht beleidigen, nur weil man diese nicht versteht, sich nie damit befasst hat oder weil sie einen ganz einfach nicht interessieren. Das ist meine Meinung. Und nun, back to topic please. Falls jemand von euch noch etwas dazu zu sagen hat, kann er dies gerne per PN tun, aber weitere offtopic-Postings werde ich nicht dulden. Greetz alcaeus |
Re: Autowerte bei Firebird setzen
Von automatisch generieren PK's halte ich auch nicht sehr viel. Eine einfache Möglichkeit ist die Verwendung einer GUID als PK, die kann man ganz einfach mit Delphi und auch aus anderen Anwendungen erzeugen:
Delphi-Quellcode:
Der PK ist dann vom Typ varchar(32) in der Firebird Datenbank.
var
MyGuid: TGUID; MyPK: string; begin CreateGUID(MyGuid); MyPK := StringReplace(Copy(GuidToString(MyGuid),2,36),'-','',[rfReplaceAll]); end; Gruß, Marcel |
Re: Autowerte bei Firebird setzen
Moin zusammen,
das Thema wird gerade richtig interessant! Marcel hat gerade Hansa´s Ansatz es vom Programm aus zu steuern mit einem praktischen Beispiel belegt. Für eine SingleUser-Anwendung ist das vom Aufwand her der ergonomischste Weg. Im kleinen Netz kann ich auch die IP´s zur Guid einbeziehen und dann ist es auch hier Rechnereindeutig. Wie das aber im Internet mit dynamischer Adressvergabe dann laufen soll ist mir allerdings nicht ganz klar. Also wie kann ich die Eindeutigkei in einem Mehrbenutzersystem wirklich garantieren. Selbst neige ich daher zu Roberts-Ansatz (ja wir sind tatsächlich mal einer Meinung!): Zitat:
So jetzt komme ich zu meinem aktuellen Problem dazu: Mir ist es n i c h t gelungen nur mit dem Generatornamen als String den aktuellen Generatorwert abzufragen o h n e eine Stored-Procedure zu bemühen. Kennt hier jemand ein eLösung ??? Grüße // Martin |
Re: Autowerte bei Firebird setzen
Hallo zusammen,
sehr interessant, was hier diskutiert wird. Darüber hab ich mir schon des öfteren mal Gedanken gemacht. Aber, was ihr in diesem Kontext leider vergessen habt ist folgendes: Die Zeos sind nicht nur für Firebird / Interbase !!! In MySQL gibts z.B. keine Generatoren, in Oracle sind es Sequenzen usw ... Das heißt, es muss ein gemeinsamer Nenner gefunden werden, um das Problem der servergenerierten Felder zu behandeln. (worüber ich mich auch schon derbe bei den Zeos-Kompos aufgeregt hab! *g*) Was es zudem in Zeos (noch) nicht gibt, ist die Möglichkeit, einen einzelnen Datensatz zu refreshen, was auch in diesen Bereich fällt. Also hab ich mir folgendes überlegt: - die TSQLUpdate-Kompo muss um einen 4. SQL erweitert werden: RefreshSQL - es muss die Möglichkeit geben, Generator/Sequence/was-auch-immer-Felder nach einem Insert zurückzubekommen --> evtl eigene Komponente? Würd mich freuen, wenn ihr dazu mal eure Meinung äußern würdet. ;-) MfG Stevie P.S.: Den Weg, ein ID-Feld in der DB zu füllen, halte ich für den saubersten, auch wenn es im Moment etwas schwierig ist. (zumindest mit Zeos) |
Re: Autowerte bei Firebird setzen
Hallo Martin,
Zitat:
SQL-Code:
Grüße vom marabu
SELECT GEN_ID(DeinGeneratorName, 0) FROM RDB$DATABASE
Nachtrag: Relational gespeichert wird in der Datenbank nur ein Zugriffsschlüssel für den Generator. Damit wird die Forderung erfüllt, dass der Generator außerhalb der Transaktionsverwaltung geführt werden muss. Die Werte können also nicht als Spaltenwerte einer Systemtabelle abgefragt werden. |
Re: Autowerte bei Firebird setzen
Moin, Jihu!
Marabu, genau der Schritt hat mir gefehlt. Klasse ! Jetzt holen wir Stevie ins Boot und bauen Roberts 'abgedrehtes' Zeug in eine abgeleitete TZQuery-Komponente ein und am Ende fällt dann auch für Hansa was praktisches an. Denn eine solche Query verliert nicht nach einem Post ihren aktuellen Datensatz sondern bleibt auf ihm stehen. Mit etwas zeitlicher Verzögerung, da noch aktuelle Aufgaben anstehen, kommt nachher mein Komponentenprototyp! Grüße // Martin |
Re: Autowerte bei Firebird setzen
Zitat:
Aber Scherz beiseite, bin mal gespannt, was da nachher kommt. :wink: P.S. Für MySQL und SQLite funktioniert das mit dem AutoInc-Werte holen. Bei MySQL wird das folgendermaßen gemacht (ZDbcMySqlResultSet.pas):
Delphi-Quellcode:
Ich denke, an dieser Stelle sollte man bei den anderen Protokollen auch ansetzen.
{**
Posts updates to database. @param Sender a cached result set object. @param UpdateType a type of updates. @param OldRowAccessor an accessor object to old column values. @param NewRowAccessor an accessor object to new column values. } procedure TZMySQLCachedResolver.PostUpdates(Sender: IZCachedResultSet; UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor); var Statement: IZStatement; ResultSet: IZResultSet; begin inherited PostUpdates(Sender, UpdateType, OldRowAccessor, NewRowAccessor); if (UpdateType = utInserted) and (FAutoColumnIndex > 0) and OldRowAccessor.IsNull(FAutoColumnIndex) then begin Statement := Connection.CreateStatement; ResultSet := Statement.ExecuteQuery('SELECT LAST_INSERT_ID()'); try if ResultSet.Next then NewRowAccessor.SetLong(FAutoColumnIndex, ResultSet.GetLong(1)); finally ResultSet.Close; Statement.Close; end; end; end; Und da dann mit der angesprochenen Eigenschaft Sequenz/Generator-Name. |
Re: Autowerte bei Firebird setzen
Moin,
also das jetzt gleich in Zeos einzuordnen dürfte aufgrund meines etwas veralteten Standes so wohl nich sinnig sein. Aber so kommt zunächst meine angeflanschte Minikomponente:
Delphi-Quellcode:
Mit Unterstützung ist soetwas sicherlich in Zeos einzuordnen und sicherlich aus dem Rohzustand zu bekommen.
unit UNIT_TzEnhDataset;
{ } { } interface uses ZIbSqlQuery, dialogs, Classes, SysUtils, DB, DBCommon; type { } { } TzEnhDataset = class( TZCustomIbSqlDataset ) private { } FGeneratorName : String; function Get_New_PID : string; public { } constructor Create ( AOwner : TComponent); override; destructor Destroy; override; procedure DoBeforeInsert; override; published { } property GeneratorName : String read FGeneratorName write FGeneratorName; end; { } TEnh_TZQuery = class(TzEnhDataset) public { } property MacroCount; property ParamCount; published { } property MacroChar; property Macros; property Params; property ParamCheck; property DataSource; property Sql; property RequestLive; property Active; end; { } implementation { } { TzEnhDataset } { } constructor TzEnhDataset.Create(AOwner: TComponent); begin inherited Create(AOwner); end; { } destructor TzEnhDataset.Destroy; begin inherited Destroy; end; { } function TzEnhDataset.Get_New_PID : string; var PIQ : TEnh_TZQuery; begin Result := '0'; if ( OV_PID_Insert ) and ( OV_PID_Insert_SQL.Text <> '' ) and ( Database <> nil ) then begin PIQ := TCR_Query.Create(nil); PIQ.Database := Database; PIQ.sql.text := 'SELECT GEN_ID(' + FGeneratorName + ', 0) FROM RDB$DATABASE'; PIQ.active := true; Result := PIQ.FieldList.Fields[0].AsString; PIQ.Active := false; PIQ.destroy; end; end; { } procedure TzEnhDataset.DoBeforeInsert; begin Edit; {Zu Testzwecken wird davon ausgegangen das PID das erst Feld ist} FieldList.fields[0].AsString := Get_New_PID; inherited DoBeforeInsert; end; { } end. Muß mir heute Mittag mal das CVS mal installieren. Soweit stelle ich das zunächst mal zur Diskussion Einen Haken hat das allerdings noch. Das Lesen des Generators erhöht ihn leider nicht, sondern erst der Post. Das hat einige Milisekunden Unsicherheit. Vielleicht hat Marabu da noch eine Idee. Grüße // Martin |
Re: Autowerte bei Firebird setzen
Hallo Martin,
Zitat:
marabu |
Re: Autowerte bei Firebird setzen
Generell würde ich es bevorzugen, den Wert nach dem Posten zu erfragen und ihn dann in das RecordSet zu holen, so wie es oben bei MySQL im Moment schon der Fall ist. Dies würde dem insert into ... returning ... into ... von Oracle entsprechen, welches imho die sauberste Lösung ist. Und all das muss in den entsprechenden dbc-units eingebaut werden.
Ich sag's hier mal in aller Deutlichkeit: Ich halte nichts davon, automatisch generierte Werte zum Client zu holen, um diese wieder in die DB zu schreiben, wenn diese das selber kann! |
Re: Autowerte bei Firebird setzen
Moin, ja das gibt doch ein Bild
Delphi-Quellcode:
Und da keimt doch so etwas wie Optimismus auf! Zeos geht mal nicht eben, werde mir das aber heute abend mal genauer anschauen.
PIQ.sql.text := 'SELECT GEN_ID(' + FGeneratorName + ', 1) FROM RDB$DATABASE';
Selbst spare ich dadurch schon eine StoredProcedure und einges an Zusatzquellcode. /Edit: Das auf AfterInsert umzustellen ist letzlich nur eine Namensumbenennung. Das analog zu den anderen Zeosroutinen zu implementieren macht natürlich sinn. Dazu muß man die aber etwas besser kennen, als das mein aktueller Stand ist. /Edit Grüße // Martin |
Re: Autowerte bei Firebird setzen
Zitat:
Den Oracle Weg gibt es in FB nicht, oder anders ausgrückt: Es gibt keinen wirklich konsistenten Weg um in FB mit autinkrementierten PKs umzugehen. Was wir hier versuchen werden ist, es wenigstens halbwegs erträglich zu machen. ;) Zitat:
FB gibt dir keine andere Möglichkeit als die hier besprochene. Zumindest keine, der ich mir bewusst bin. ;) |
Re: Autowerte bei Firebird setzen
Nur damit nicht der Verdacht aufkommt, ich hätte viel Trubel um nüchts gemacht...
Ich bin gerade in einer dieser wochen, in denen man höchsten zum Schlafen nach Hause kommt. Bis zum WE werde ich aber Zeos ausgecheckt und ein wenig darin gestöbert haben. Ich hoffe dass ich am WE die Zeit dafür finde. sollte sich ja bestimmt auf <200 Zeilen belaufen. Mal sehen was man da noch rausholen kann. <g> |
Re: Autowerte bei Firebird setzen
Moin, reichlich Spätmoin,
habe mir inzwischen das CVS erstmal installiert, aber das wir hier alle nicht zum Hobby programmieren dürfte wohl inzwischen klar sein. Da sind verzögerungen wohl zu aktzeptieren. Wenn ich das sehe hat Stevie ja schon eine analoge pas - Datei rausgescuht. Komme da aber auch nur nach Feierabend zu, da Zeos doch inzwischen eine gewisse Komplexität erreicht hat. Fazit: noch dran ! Gute Nacht // Martin |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:15 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