Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Primarykey, wie vergeben (https://www.delphipraxis.net/77239-primarykey-wie-vergeben.html)

BenjaminH 16. Sep 2006 18:46

Datenbank: Firebird Embedded • Version: 1.5.3 • Zugriff über: IBX

Primarykey, wie vergeben
 
Nach welchen Kriterien soll ich beim erstellen eines neuen Datensatzes den PrimaryKey vergeben?
Oder kann ich in der Datenbank einstellen, dass das automatisch passiert?

Am einfachsten dachte ich es mir so, dass ich den höchsten Suche und einfach eins dazu zähle.
Aber mit welcher Abfrage finde ich am effizientesten den höchsten PK?

Viele Grüße
Benjamin

Thanatos81 16. Sep 2006 18:48

Re: Primarykey, wie vergeben
 
Was benutzt du denn als PrimaryKey? Falls es eine Laufende Nummer oder GUID sein soll, mach dich mal über Trigger und Generatoren schlau. Die können als Gespann nämlich automatisch den PrimarayKey vergeben, ohne dass man sich drum kümmern muss ;-)

BenjaminH 16. Sep 2006 19:04

Re: Primarykey, wie vergeben
 
Addiert ein Generator generell 1 dazu?
irgendwie hab ich das jetzt so verstanden, weil man bei IBExpert immer nur den Namen und den Startwert angeben kann.
Trigger scheinen mir ein sehr mächtiges Werkzeug zu sein, ich glaube damit kann ich noch ein paar nette Sachen machen.

//Edit
Ich hab jetzt den Generator und Trigger nach bestem Gewissen erstellt und bekomme trotzdem dauernd die Meldung "Feld 'PRIMARYKEY' muss einen Wert haben."

mkinzler 16. Sep 2006 19:15

Re: Primarykey, wie vergeben
 
Zitat:

Addiert ein Generator generell 1 dazu?
Nein ein Generator addiert nichts sondern ist die variable, die den nächsten Wert enthält. Um vieviel erhöht wird kann man in GEN_ID() angeben
Zitat:

irgendwie hab ich das jetzt so verstanden, weil man bei IBExpert immer nur den Namen und den
Zitat:

Startwert angeben kann.
dito
Trigger scheinen mir ein sehr mächtiges Werkzeug zu sein, ich glaube damit kann ich noch ein paar nette Sachen machen.
Wie der name schon sagt, werden sie automatisch bei einem bestimmten Ereignis aufgerufen. Die Erhöhung eines Generators ist nur eine Anwendung. das Verhindern oder Loggen von Datenmanipulationen eine andere.

mkinzler 16. Sep 2006 19:16

Re: Primarykey, wie vergeben
 
Zitat:

Ich hab jetzt den Generator und Trigger nach bestem Gewissen erstellt und bekomme trotzdem dauernd die Meldung "Feld 'PRIMARYKEY' muss einen Wert haben."
Wie setzt du den Wert? Du darfst den Key nicht setzen.

BenjaminH 16. Sep 2006 19:21

Re: Primarykey, wie vergeben
 
ich setze ihn garnicht, d.h. ich habe ein TDBText
Aber sonst wird nirgends speziell auf den Primarykey eingegangen.

mkinzler 16. Sep 2006 19:22

Re: Primarykey, wie vergeben
 
Und mit aws ist der DBText verknüpft?

BenjaminH 16. Sep 2006 19:25

Re: Primarykey, wie vergeben
 
Mit dem DataSource in den auch eingefügt wird
//Edit
Ich habe jetzt versucht die DBText-Komponente
beim Post und beim ApplyUpdate und beim Insert zu deaktivieren, den Fehler gibts jedesmal trotzdem.

mkinzler 16. Sep 2006 19:35

Re: Primarykey, wie vergeben
 
Ist die TDBText ( über die dataSource) an eine TTable oder eine TQuery-Komponente gebunden?

BenjaminH 16. Sep 2006 19:44

Re: Primarykey, wie vergeben
 
An TTable, aber ich glaube ich habs jetzt erledigt.
Ich hab das "Not Null" des Feld des Primarykeys deaktiviert, damit müsste Delphi meine Befehle durchlassen.
Und NULL wird es trotzdem nie, da der Trigger sich ja darum kümmert.

//Edit
mh, jetzt ist dann, bis ich das Programm Neustarte der PK leer, wie kann ich dafür sorgen, dass die Datenbank das synchronisiert?

mkinzler 16. Sep 2006 19:46

Re: Primarykey, wie vergeben
 
Zitat:

Zitat von BenjaminH
An TTable, aber ich glaube ich habs jetzt erledigt.
Ich hab das "Not Null" des Feld des Primarykeys deaktiviert, damit müsste Delphi meine Befehle durchlassen.
Und NULL wird es trotzdem nie, da der Trigger sich ja darum kümmert.

Es wäre aber besser das NOT NULL zu lassen und die Setzen des Feldes am Client zu verhindern oder da schon den richtigen wert zu setzten (z.B. über Sequenz).

BenjaminH 16. Sep 2006 19:49

Re: Primarykey, wie vergeben
 
Zitat:

Zitat von mkinzler
Es wäre aber besser das NOT NULL zu lassen und die Setzen des Feldes am Client zu verhindern

Ja, aber daran scheiterts leider, oder habe ich da eine Lösung übersehen?

mkinzler 16. Sep 2006 19:52

Re: Primarykey, wie vergeben
 
Ersetzte die Table durch ein TIBQuery und fülle im UpdateSql nur die Felder, die du setzen willst.

Hansa 16. Sep 2006 20:01

Re: Primarykey, wie vergeben
 
Ich glaube, da muß man etwas weiter ausholen. Oder wie ist es möglich einen Trigger so zu überlisten, daß der "PK leer bleibt". :shock: Also : ein Generator ist eine Variable, die in der Datenbank liegt. In FB fehlt nun ein Datentyp automatisch hochzuzählender Werte. Deshalb macht man das üblicherweise mit einem Trigger. Aber um IDs als PK herzustellen darf das natürlich nur beim neueinfügen eines Datensatzes passieren und nicht bei einer Änderung :

Teste das hier mal in der Script-Executive :
SQL-Code:
/******************************************************************************/
/****              Generated by IBExpert 16.09.2006 20:43:10               ****/
/******************************************************************************/

SET SQL DIALECT 3;

SET NAMES ISO8859_1;

CREATE GENERATOR GEN_TEST_ID;

SET TERM ^ ;


CREATE TRIGGER TEST_BI0 FOR TESTTABLE
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
  IF (NEW.ID IS NULL) THEN
    NEW.ID = GEN_ID(GEN_TEST_ID, 1);
END
^


SET TERM ; ^
So, das Teil schlägt jetzt bei jedem Insert zu und erhöht den Generator einfach um 1. Je nach Tabellenstruktur, kann da jedes Tabellenfeld auch vorbesetzt werden usw. Stop, Du brauchst doch nur den Feldeditor. Klicke mal ein Feld an (Spalte PK). Da steht oben alles was man braucht : Generator, Autoincrement (-> Trigger) und wenn die Namen richtig vergeben werden, dann wird so was wie oben automatisch zusammengebaut.

P.S.: der Vollständigkeit halber noch zur Theorie. 8) In IB/FB unterliegt alles der Transaktionskontrolle, was bedeutet, daß alle Datenänderungen bestätigt, oder auch bis zu einem bestimmten Punkt zurückgenommen werden können. Einzige Ausnahme sind die Generatoren. Wenn selbst das Löschen einer ganzen Tabelle mit Rollback zurückgenommen werden kann, so betrifft das nicht die Generatorenwerte ! Die bleiben wie sie zuletzt waren ! Man sieht manchmal, daß die für reelle Daten mißbraucht werden, z.B. Rechnungsnummern.

P.S.2 : teste das zuerst mal besser mit IBExpert und nicht mit Delphi ! Denn es gilt : wer den Primary Key vergißt oder falsch behandelt wird schwer bestraft werden ! :stupid:

BenjaminH 16. Sep 2006 20:08

Re: Primarykey, wie vergeben
 
ok, vielen Dank :thumb:
Super Hilfe von dir, ich glaub jetzt habe ich alles, was ich für mein Programm brauche durch!

@Hansa, danke für die nochmaligen ausführungen!
Was bedeutet
Code:
SET TERM ^ ;
und wofür sind die ganzen ^

Elvis 16. Sep 2006 20:34

Re: Primarykey, wie vergeben
 
Einfach in IBExpert autoinc in der Columns view anklicken. Dort legt er für dich die Trigger an.

Ansonsten kann ich dir bei Firebird 2 nur empfehlen nicht auf alles zu hören, ws die alten FB-Hasen sagen. :mrgreen:

Firebird 2 hat eine returning clause, das heißt du kannst dir direkt aus einem INSERT den neuen PrimaryKey holen, den ein Trigger besetzt hat.
Dadurch kannst du die Lücke schließen, die der Standard-Trigger aus IBExpert (also auch Hansas) offen lässt.
In diesem klassischen IB/FB-PK-Trigger wird nur dann der PK aus dem Generator geholt wenn kein Wert für den PK angegeben wurde.
IMHO ist das ziemlich fehleranfällig, da später eine Kollision entstehen kann.

Stell' dir vor, dein Generator steht auf 3. Bei einem INSERt wird jetzt aber eine 5 für den PK eingefügt.
Der blauäugige Trigger von oben wird den Wert in deine Tabelle lassen und alles scheint Friede-Freude-Eierkuchen.
Jetzt werden noch 2 Datensätze angelegt, bei denen kein Wert für den PK angegeben wurde.
  1. Generatorwert 3 + 1 -> 4 als PK in die Tabelle -> ok
  2. Generatorwert 4 + 1 -> 5 in die Tabelle -> kaboom!
    5 wurde vorhin schon eingefügt!

Oki, was machen?
Du lässt dir natürlich weiterhin den Trigger von IBExpert anlegen. (Man ist ja faul :mrgreen: )
IBExpert lässt dich aber direkt den Code editeren und du löschst die Zeile mit dem "if :new.blabla is null then" einfach raus.

Ein INSERT sieht jetzt so aus:
SQL-Code:
INSERT INTO DeineTabelle
(
  SomeField
)
VALUES
(
  :SomeField
)
RETURNING ID INTO :ID
Solange der Trigger läuft kannst du dir nun sicher sein immer einen korrekten PK einzufügen und du bekommst in auch direkt bei einem INSERT zuück. :)

Zitat:

Zitat von BenjaminH
Was bedeutet
Code:
SET TERM ^ ;
und wofür sind die ganzen ^

Du legst am Anfang eines Skriptes fest was der Statement seperator ist.
Jedesmal wenn dieser String auftaucht wird das Schnipselchen davor als einzelnes Statement abgesetzt.

Hansa 17. Sep 2006 00:25

Re: Primarykey, wie vergeben
 
Natürlich kann man Release Candidates benutzen. Von mir kommen solche Tips jedenfalls nicht. Wer weiß ? FB 2.0 kann Rückgaben an das Programm liefern, aber das ist IMHO der falsche Weg. Lasst die DB solche Sachen intern regeln und basta. Warum soll mir das Programm direkt die ID liefern ? Solche Fälle gibts schon, aber den Pk VON HAND zu ändern, wer zwingt einen dazu ? Und @RG : Thema ist wohl nicht nicht mehr akut, deshalb besser keine Verwirrung stiften. :mrgreen:

Elvis 17. Sep 2006 01:35

Re: Primarykey, wie vergeben
 
Zitat:

Zitat von Hansa
Natürlich kann man Release Candidates benutzen. Von mir kommen solche Tips jedenfalls nicht. Wer weiß ? FB 2.0 kann Rückgaben an das Programm liefern, aber das ist IMHO der falsche Weg. Lasst die DB solche Sachen intern regeln und basta.

Es ist ja nicht so, dass ich nicht ständig auf dein (nicht vorhandenes) Fachwissen hinweise. Aber gerade da wo selbst ich erwartet hätte, dass du weißt wovon du sprichst zeigt dein letzter Satz dass es eben nicht so ist. ;)
Wenn ich im Programm einen PK holen muss nur damit ich nach dem Insert weiß wie der PK des neuen Datensatzes lautet, dann mag das alles Mögliche sein:
Umständlich? Ja.
Fehlerträchtig? Auf jeden Fall!
"DB intern geregelt"? Sicherlich nicht.
Zitat:

Warum soll mir das Programm direkt die ID liefern ?
Muss auch nicht. Wenn man die ID nicht wissen will, dann läuft es trotzdem, aber was wenn doch?
Ich wollte nur einwenden, dass der Standard-Trigger, den FB'ler seit Jahren benutzen nur aus einem Grund trotz der klaffenden Lücke so geschrieben wurde: Es gab kein Returning. Und mit FB2 gibt es keinen Grund diesen Unfug weiterhin zu betreiben. ;)
Zitat:

Thema ist wohl nicht nicht mehr akut, deshalb besser keine Verwirrung stiften.
Ben mag ein DB-noob sein, aber ich denke doch dass er nicht blöd ist. Und es war eigentlich nur eine Klitzekleinigkeit auf die ich hier hinwies[1]. Ich denke er wird schon verstanden haben. Und wenn nicht wird er sicherlich mit einem höflichen "Hä?" fragen können. ;)

Mensch Hansa, nimm' dir noch 'n Bier und halte den Ball einfach etwas flacher...



[1]neben meiner typischen allergischen Reaktion auf Ignoranz á la Hansa. :angle2:

hoika 18. Sep 2006 07:05

Re: Primarykey, wie vergeben
 
Hallo,

das Set Term in der ersten Zeile setzt den Terminator vojn ; auf ^
In der vorletzten Zeile wird dann das Scriot abgeschlossen
durch eben diesen Terminator.
Notwendigi ist es, weil das Script aus mehreren Zeilen besteht,
und intern das Semikolon schon als Befehlstrenner benutzt wird.

Über ibexpert kannst du die Trigger übrigens auch ohne das Set Term
erzeugen / bearbeiten.

Noch eine Sache zu prim. key + TTable.
Spätestens wenn du die ID deines neuen Datensatzes sofort nach dem Append
brauchst, hast du ein Problem.
Aus diesem Grund hole ich mir den jeweils neuen prim. key eines Datensatz vor
dem Eintragen selber.

SQL-Code:
CREATE PROCEDURE BILL_COSTCENTER_NEWID
RETURNS (
    NEWID INTEGER)
AS
begin
  newid=gen_id(Gen_Bill_CostCenter,1);
end
BILL_COSTCENTER_NEWID ist ein Generator (Sequenz)

Die Stored Procedure rufe ich auf und schon habe ich meinen neuen Wert.

SQL-Code:
function Table_GetNewId__DB(const theDataBaseName, theTableName: String;
  var theNewId: Longint; var theErrorStr: String): Boolean;
var
  SP: TStoredProc;
begin
  Result:= False;

  theNewId:= -1;
  theErrorStr:= '';

  try
    SP:= TStoredProc.Create(NIL);
    try
      SP.DataBaseName:= theDataBaseName;
      SP.StoredProcName:= UpperCase(theTableName)+'_NEWID';
      SP.ExecProc;

      theNewId:= StrToInt(SP.Params[0].AsString);

      Result:= True;
    finally
      SP.Free;
    end;
  except
    on E: Exception do
    begin
      theErrorStr:= E.message;
    end;
  end;
end; { Table_GetNewId__DB }
Die Methode ght übrigens davon aus, das die Generatoren für die Tabellen immer
im Format
TableName + '_NewId' vorliegen.

Heiko


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:59 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