Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Create Table mit Firebird und ZEOS, wie richtig machen (https://www.delphipraxis.net/146737-create-table-mit-firebird-und-zeos-wie-richtig-machen.html)

Jens Hartmann 26. Jan 2010 11:14

Datenbank: Firebid • Version: 2.1 • Zugriff über: ZEOS

Create Table mit Firebird und ZEOS, wie richtig machen
 
Hallo zusammen,

ich hab ml wieder eine Frage zum erstelle von Tabellen während der Laufzeit. Es ist kein Problem gewesen, für mich dieses zu realisieren. Allerdings verstehe ich es noch nicht so richtig, wie ich einen PK inkl. Trigger und Generator anlege und vorallem wie ich vorher prüfen kann, ob die Tabelle vieleicht schon existiert. Ich habe über die DR und DP schon gesucht, allerdings noch nicht mit dem richtigen Erebnis.

Hier habe ich zwar einen Thread gefunden der dies beschreibt, aber so richtige weiß ich nicht ob das das Richtige ist.
Firebird
Ich möchte während dem Programm eine Tabelle erstellen, die folgende Eigenschaften hat, und vorher allerdings prüfen, ob Sie eventuell schon vorhanden ist.
Code:
Tabellenname "AREA" FELD1 "ID" FELD2 BEREICH
Das erstellen, habe ich folgdermaßen realisiert.
Delphi-Quellcode:
  Qry_Create.SQL.Text := 'CREATE TABLE AREA (ID integer, Bereich VarChar(50)'
Delphi-Quellcode:
var
  SL: TStrings;
  index: Integer;
begin
  SL := TStringList.Create;
  try
    DBCon.GetTableNames(SL, False);
Jetzt die Frage, wie gehe ich jetzt da mit weiter vor. Wie erstellen ich den Trigger und GEN richtig. Wie prüfe ich richtig ob die Table schon vorhanden ist. Gibt es irgenwie dazu ein Tutorial für ZEOS und Firebird, wo das erklärt wird.

Danke schon mal

Gruß Jens

DeddyH 26. Jan 2010 11:28

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Ich möchte Dir die Firebird-FAQ ans Herz legen. U.a. findet sich dort auch dieser Artikel: How to create a table only if it does not exist?

Hth

Jens Hartmann 26. Jan 2010 12:16

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Hallo DeddyH,

danke erstmal für die schnelle Hilfe. Die Seite kenne ich schon, und die Funktion habe ich auch schon versucht. Allerdings, bekomme ich bei folgendem Code eine Fehlermeldung zurück.

Delphi-Quellcode:
Qry_CreateTableArea.SQL.Text :=
'EXECUTE BLOCK AS BEGIN if (not exists(select * from AREA where rdb$relation_name = "EMPLOYEE")) then execute statement "CREATE TABLE AREA ( ID Integer, BEREICH String );"';
Gruß Jens

DeddyH 26. Jan 2010 12:20

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Da fehlt auch zumindest das END zum AS BEGIN.

Jens Hartmann 26. Jan 2010 12:28

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Ja, richtig. Ist trotdem nicht besser. Gibt es denn nicht irgendwie einen Compiler, der mir das wie bei einem Delphi-Code anzeigt, wenn da was noch nicht stimmt.

Ich habe irgendwie immer Problem mit den Codeteilen SQL.

Gruß Jens

DeddyH 26. Jan 2010 12:35

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Besorg Dir doch einfach die Personal von IBExpert, die nimmt Dir schon einiges an Arbeit ab (z.B. Codegenerierung für Metadaten).

Jens Hartmann 26. Jan 2010 12:54

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Hab ich, damit erstell ich auch bislang meine Tabellen. Allerdings, wollte ich das erstellen der Tabellen auch über die Aplication realisieren, um gewisse Änderungen oder Neuerungen in die DB zu integrieren.

Mein Problem ist, die Funktion, wie die Table erstellt wird, finde ich ja scheinbar unter DLL im Table Explorer. Allerdings, komme ich nicht so richtig damit klar, diesen Code in Delphi zu integrieren.

Gruß Jens

DeddyH 26. Jan 2010 12:58

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Es gibt doch da auch die schöne Funktion "Metadaten extrahieren" oder so ähnlich, die müsste auch in der Personal verfügbar sein. Damit wird Dir ein komplettes DB-Script erstellt samt aller Schlüssel. Das solltest Du Dir mal ansehen.

hoika 26. Jan 2010 13:16

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Hallo,

im obiegn Link steht doch asudrücklich

and you can't use IF outside of PSQL, you can use EXECUTE STATEMENT in PSQL.

PSQL = Stored Procedure

Aber
SQL-Code:
select 1 from rdb$relations
where rdb$relation_name = 'EMPLOYEE')
Das ist eine normale Abfrage und ergibt 1, falls die Tabelle existiert.


Analog

SQL-Code:
Select Count(*) From RDB$Triggers
Where RDB$Trigger_Name='MyTriggerName'
Hier mal Count(*)

Analog hierzu die Generatoren

Tabelle RDB$GENERATORS
FeldName RDB$GENERATOR_NAME


Die RDB$-Tabellen sind übrigens System-Tabellen,
die sich auch unter dem oben erwähnten IBExpert anzeigen lassen
und gehören zum sogenannten Schema der Datenbank.


Heiko

DeddyH 26. Jan 2010 13:19

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Du musst aber auch bis zum Ende lesen ;)
Zitat:

This is fine, but now it seems you need to create a special stored procedure for this. Well, we use another new feature: EXECUTE BLOCK to make it a single statement:

SET TERM !! ;
EXECUTE BLOCK AS BEGIN
if (not exists(select 1 from rdb$relations where rdb$relation_name = 'EMPLOYEE')) then
execute statement 'create table employee ( id integer );';
END!!
SET TERM ; !!


Those SET TERM statements are only needed if you work from an administration tool like isql or FlameRobin. If you run it from your application code, just send the EXECUTE BLOCK block as a single statement.

Jens Hartmann 26. Jan 2010 18:55

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Zitat:

Zitat von DeddyH
Those SET TERM statements are only needed if you work from an administration tool like isql or FlameRobin. If you run it from your application code, just send the EXECUTE BLOCK block as a single statement.

ich habe übrigens das ganze bis zum Ende gelesen. Ich habe das vieleicht nur nicht ganz verstanden. Also wenn ich das mit meinen Englischkenntnissen richtig verstehe, bedeutet das folgendes..
SQL-Code:
SET TERM
wird nur in Verbindung mit isql or FlameRobin benötigt. In meiner Delphi Aplication muss ich den EXCECUTE BLOCK als einzelnen Block senden. Entweder habe ich das falsch verstanden oder sonst einen Fehler in meinem Code. Das Create, den Trigger etc. habe ich übrigens alles alleine "DURCH LESEN" realisiert.
Exceptionbehandlung und so muss allerdings noch angepasst werden..
Delphi-Quellcode:
Qry_CreateTableArea.SQL.Text :=
'CREATE GENERATOR GEN_AREA_ID; ';
  Qry_CreateTableArea.ExecSQL;
  DM_PS.ConPSConfig.Commit;
Qry_CreateTableArea.SQL.Text :=
'CREATE TABLE AREA (ID ID_DOM, BEREICH TEXT_DOM)';
  Qry_CreateTableArea.ExecSQL;
  DM_PS.ConPSConfig.Commit;
Qry_CreateTableArea.SQL.Text :=
'ALTER TABLE AREA ADD CONSTRAINT PK_AREA PRIMARY KEY (ID) USING INDEX ID';
  Qry_CreateTableArea.ExecSQL;
  DM_PS.ConPSConfig.Commit;
Qry_CreateTableArea.SQL.Text :=
'CREATE OR ALTER TRIGGER TRI_AREA FOR AREA '+
'ACTIVE BEFORE INSERT POSITION 0 '+
'AS '+
'BEGIN '+
  'IF (NEW.ID IS NULL) THEN '+
    'NEW.ID = GEN_ID(GEN_AREA_ID,1);END';
  Qry_CreateTableArea.ExecSQL;
  DM_PS.ConPSConfig.Commit;

  Qry_CreateTableArea.Close;
  Qry_CreateTableArea.SQL.Text :=
  'INSERT INTO AREA (ID,BEREICH)VALUES(:Id,:Bereich)';
  Qry_CreateTableArea.ParamByName('Id').Value := 1;
  Qry_CreateTableArea.ParamByName('Bereich').Value := 'Verbrauchermarkt';
  Qry_CreateTableArea.ExecSQL;
  DM_PS.ConPSConfig.Commit;
except
  Form1.ServiceMemo.Lines.Add('Fehler beim erstellen von Tabelle Bereiche');
end;
end;
Das mit der Abfrage ob die Tabelle vorhanden ist klappt allerdings nicht.
Delphi-Quellcode:
Qry_CreateTableArea.SQL.Text :=
'SELECT 1 FROM rdb$relations where rdb$relation_name = "AREA"';
Qry_CreateTableArea.Open;
Wie muss ich das mit dieser Anweisung denn verstehen. was und wo befinden sich diese beiden Datenbanken/Tabellen oder so. Wenn ich das richtig verstanden habe, sind diese in meiner DB integriert. Mit dem Befehl...
Delphi-Quellcode:
Con_Info.GetTableNames
werden mir diese auch Angezeigt. Aber verstehen tue ich die Funktion nicht und eine Exception bring sie auch. Vieleicht ist ja jemand in der Lage mir das mal zu verdeutlichen.

Gruß Jens

mkinzler 26. Jan 2010 19:19

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
SET TERM ändert das Terminierungsymbol, das ist wichtig um Befehlsende vom nde eines Blockes o.ä trennen zu können

Jens Hartmann 26. Jan 2010 19:49

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Zitat:

Zitat von mkinzler
SET TERM ändert das Terminierungsymbol

Versteh ich nicht so recht. Aber ich hoffe das ich verstanden habe, das ich das bei Delphi nicht brauche.

alex517 26. Jan 2010 20:46

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Zitat:

Zitat von Jens Hartmann
Das mit der Abfrage ob die Tabelle vorhanden ist klappt allerdings nicht.
Delphi-Quellcode:
Qry_CreateTableArea.SQL.Text :=
'SELECT 1 FROM rdb$relations where rdb$relation_name = "AREA"';
Qry_CreateTableArea.Open;

Es ist immer von Vorteil sich die Fehlermeldung anzusehen, oder wenigstens zu posten.
Ich vermute mal die lautete
Code:
Column unknown.
AREA.
Das liegt an den doppelten Anführungsstrichen. Die Angaben innerhalb der doppelten A.. interpretiert
Firebird als Feldnamen. Deshalb auch "Column unknown".
Du suchst aber einen String 'AREA' im Feld RDB$RELATIONS_NAME in der Tabelle RDB$RELATIONS!
Und ein String muß in einfache Anführungsstrichen eingeschlossen sein.

Zitat:

Zitat von Jens Hartmann
Wie muss ich das mit dieser Anweisung denn verstehen. was und wo befinden sich diese beiden Datenbanken/Tabellen oder so. Wenn ich das richtig verstanden habe, sind diese in meiner DB integriert. Mit

In einer Firebird-Datenbank existieren ein ganze Reihe Systemtabellen RDB$.., MON$...
In den RDB$-Tabellen werden alle Metadaten, also die Struktur der Datenbank verwaltet.
D.h. deine Tabelle 'AREA' findest du in der Tabelle RDB$RELATIONS, die dazu gehörigen
Felder in der Tabelle RDB$RELATION_FIELDS wieder.
Diese Systemtabelle können ganz normal mit SELECT abgefragt werden.
Angezeigt werden die Systemtabellen z.B. bei IBExpert nur, wenn man das entsprechende Häkchen für "Systemtabellen anzeigen" setzt.

Achtung! Es ist sicher lehrreich sich die Tabellen anzusehen. Auf keinen Fall sollte man aber die
Inhalte der Tabelle ändern. Es sei den man weiß genau was man macht und hat ein Backup der Datenbank.
Ich habe es bisher unterlassen, bis auf eine Ausnahme. ;-)

alex

Jens Hartmann 26. Jan 2010 21:05

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Zitat:

Zitat von alex517
Es ist immer von Vorteil sich die Fehlermeldung anzusehen, oder wenigstens zu posten.

Ich vermute mal die lautete
Code: markieren
Column unknown.
AREA.
Ja, das ist so. Aber dann steh ich entweder auf dem Schlauch oder ich weis nicht. Wie schreibe ich das den dann in Delphi mit den '' Anfhrungszeichen. Delphi akzeptiert das doch so nicht...
Delphi-Quellcode:
Qry_CreateTableArea.SQL.Text :=
'SELECT 1 FROM rdb$relations where rdb$relation_name = 'AREA';
Qry_CreateTableArea.Open;
Weil des SQL String muss doch auch in '' stehen.

Gruß Jens

alex517 26. Jan 2010 21:10

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Zitat:

Zitat von Jens Hartmann
Wie schreibe ich das den dann in Delphi mit den '' Anfhrungszeichen.

einfach ZWEI einfach Anführungzeichen.
Delphi-Quellcode:
Qry_CreateTableArea.SQL.Text :=
'SELECT 1 FROM rdb$relations where rdb$relation_name = ''AREA''';
Qry_CreateTableArea.Open;
alex

alex517 26. Jan 2010 21:11

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
noch was zum Thema:

Mit zunehmender Komplexität der Datenbank wird es immer schwieriger werden
die Metadaten auzupassen.
Es müssen Abhängigkeiten der Constrains, Abhängigkeiten durch Tabelle und Felder die
in Triggern, Prozeduren und View verwendet werden usw. beachtet werden.
Diese "Objecte" müssen ggf. deaktiviert/auskommentiert und dann in der richtige Reihenfolge
wieder aktiviert werden.
Für diese Zwecke liefere ich immer eine Standard-Datenbank aus, mit der
dann die Kundendatenbank durch "fertige" Tools verglichen wird.
Diese Tools liefern mir ein fertiges SQL-Script mit den erforderlichen Änderungen,
welches ich nur noch auszuführen brauche.

DatabaseComparer-Tools z.B.:

- IBExpert Prof.-Version
- IBEScript.exe, IBEScript.dll

oder

- Database Comparer von CleverComponents

hoika 27. Jan 2010 06:31

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Hallo,

mit den Strings ist das halt so eine Sache,
das geht dann mit DateTime weiter.
Also am besten gleich Parameter verwenden

Delphi-Quellcode:
Qry_CreateTableArea.SQL.Text :=
'SELECT 1 FROM rdb$relations where rdb$relation_name = :TableName';
Qry_CreateTableArea.ParamByName('TableName').AsString:= 'Area';
Der Doppelpunkt vor TableName zeigt an,
dass es ein Parameter ist.


Was ich nicht verstehe ist, dass du einen aufen Zeit mit Create Table verwendest,
ohne eine Zeile "richtigen" Code geschrieben zu haben.
Falls sich in der Tabelle noch etwas ändern sollte,
fängst du wieder an.

Schnapp dir IBExpert, lege dort komfortabel die Tabellen an
und wenn du mit dem Programm fertig bist,
kannst du dir immer noch überlegen, wie du die DB erzeugst / auslieferst.


Heiko

alex517 27. Jan 2010 07:21

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Zitat:

Zitat von hoika
mit den Strings ist das halt so eine Sache,
das geht dann mit DateTime weiter.
Also am besten gleich Parameter verwenden
Delphi-Quellcode:
Qry_CreateTableArea.SQL.Text :=
'SELECT 1 FROM rdb$relations where rdb$relation_name = :TableName';
Qry_CreateTableArea.ParamByName('TableName').AsStrng:= 'Area';

100% Zustimmung :-D
alex

haentschman 27. Jan 2010 08:06

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Zeos hat doch eine Komponente für die Metadaten dabei. Die stellst du einfach ein, welche du sehen willst und hast als Ergebnismenge z.B. die Tabellen. Darin kannst du dann suchen, ob vorhanden oder nicht und entsprechend reagieren.

:hi:

Jens Hartmann 27. Jan 2010 10:03

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Zitat:

Zitat von hoika
Was ich nicht verstehe ist, dass du einen haufen Zeit mit Create Table verwendest,
ohne eine Zeile "richtigen" Code geschrieben zu haben.
Falls sich in der Tabelle noch etwas ändern sollte,
fängst du wieder an.

Schnapp dir IBExpert, lege dort komfortabel die Tabellen an
und wenn du mit dem Programm fertig bist,
kannst du dir immer noch überlegen, wie du die DB erzeugst / auslieferst.

Das ist doch alles kein Problem mehr für mich. So mache ich es ja bislang. Es ist nur so, das sich meine Software weiterentwickelt hat, und ich um zusätzliche Tabellen und Einträge in die Datenbank nicht mehr umher komme.
Bislang habe ich die Datenbank bei der Auslieferung fertig Konfiguriert mit Ausgeliefert und dann beim Kunden an dessen Einstellungen angepasst.
Da ich aber jetzt zusätzliche Tabellen und Einträge in die Datenbank integriert habe, muss ich ja einen Weg finden, diese auch bei meinen vorhandenen Kunden zu integrieren. Und da ist mir halt der Gedanke gekommen, dies auf diesem Weg zu machen.
Ich würde ein Software-Update ausliefern, dieses Installieren und anschließend in den neuen Menüfunktionen beim Konfigurieren in die DB schauen, und bei nicht vorhanden (alte Software) diese einfach erzeugen lassen.
Somit gehe ich doch dem Problem aus dem Weg, die vorhanden Kundenspezifische Konfiguration erneut durchführen zu müssen. Würde ich die DB gegen die neue austauschen, wären ja auch dessen Einstellungen weg.

Gruß Jens

hoika 27. Jan 2010 10:49

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Hallo,

ahhh so ;)

Dann ist das OK.

In der Praxis hat sich bei mir bewährt,
in der DB eine DB-Nummer hochzuzählen.

Anhand der DB-Nummer weiss
1. das Programm, welche Tabellen/Felder vorhanden sind
2. die DB-Update-Routine, was noch zu aktualisieren ist

Die Nummer steht in einer eigenen Tabelle
DBInfo
DBNo Integer

Da das Aktualisieren und das Hochsetzen der DB-Nummer
in einer gemeinsamen Transaktion erfolgt, kann nichts schiefgehen.


Heiko

schlecki 27. Jan 2010 11:27

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Zitat:

Zitat von hoika
Da das Aktualisieren und das Hochsetzen der DB-Nummer
in einer gemeinsamen Transaktion erfolgt, kann nichts schiefgehen.
Heiko

Zumindest beim Firebird - ich glaube auch bei den anderen großen DBMS - läuft die DDL (Data Definition Language) nicht in einer Transaktion!

hoika 27. Jan 2010 11:32

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Hallo,

das glaube ich nicht.

Was du vielleicht meinst sind die Generatoren(Sequenzen),
ein gen_id(gen_x,1) ist in der Tat per Rollback nicht rückgängig machbar.

StartTransaction
Create Table Tab_X
RollBack

=> Tab_X existiert nicht.

Auch die Metadaten sind Teile der MGA.


Heiko

schlecki 27. Jan 2010 11:48

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
hm, ist das neu?

Ich meine mich erinnern zu können, etwas ähnliches wie du verwenden zu wollen und es scheiterte genau an dieser Stelle. Wobei das auch schon eine Weile her ist.

hoika 27. Jan 2010 12:14

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Hallo,

also zumindestens ein Alter Table Add kann ich per RollBack wieder "zurücksetzen".
Das sollte bei Create Table aber auch so sein.

Kommt auf einen Versuch an ...


Heiko

Jens Hartmann 27. Jan 2010 13:12

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Danke erstmal für die viele Hilfe,

kann mir vieleicht mal jemand was zu der Metadaten Komponente sagen. Oder gibt es da irgendwo eine Beschreibung oder ein Tutorial zu. Ich möchte mir die Kompo gerne mal genauer ansehen. Allerdings kann ich in folgendem Tutorial...



leider nur das hier finden..
Code:
Mit dieser speziellen TDataSet-Komponente ist es möglich, auf die Metadaten einer Datenbank zuzugreifen, wie z. B. Tabellen, Spalten, Indizes, etc.
@hoika: Danke für den Tip mit der DB-Nummer. Das werde ich aufjedenfall auch so machen.

Gruß Jens

Jens Hartmann 28. Jan 2010 17:36

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Hallo zusammen,

ich habe jetzt mal versucht das ganze umzusetzen. Es funktioniert auch so wie ich mir das Vorgestellt habe. Allerdings frage ich nach dem Abfragen ob die DB "DBINFO" existiert mit
Delphi-Quellcode:
  if Qry_DataVersion.RecordCount = 0 then
    begin
ab, ob die DB existiert. Und ich vermute das es nicht der Richtige weg ist. Hier mal meine Funtkion mit der DB-Version, wie "hoika" vorgeschlagen hat.
Delphi-Quellcode:
//Anweisung in Form.Create von Form1
  if DM_Update.DatenbankVersion(Vers) = true then
    begin
    ...
//Neues Unit DataManagement. Soll die komplette Verwaltung der Datenbank in Zukunft übernehmen
unit DataManagement;

interface

uses
  SysUtils, Classes, ZConnection, DB, ZAbstractRODataset, ZAbstractDataset,
  ZDataset, Dialogs;

type
  TDM_Update = class(TDataModule)
    Con_UpdateConfig: TZConnection;
    Con_UpdateSecurdat: TZConnection;
    Con_UpdateUser: TZConnection;
    Qry_DataVersion: TZQuery;
    Qry_UpdateVersion: TZQuery;
  private
    { Private-Deklarationen }
  public
    function DatenbankVersion(var Version : Integer) : Boolean;
    function UpdateVersion(var Version : Integer) : Boolean;
    function UpdateDataDB(var Version : Integer) : Boolean;
    function UpdateUserDB(var Version : Integer) : Boolean;
    { Public-Deklarationen }
  end;
var
  DM_Update: TDM_Update;

implementation
uses
Alarm;

{$R *.dfm}
function TDM_Update.DatenbankVersion(var Version : Integer) : Boolean;
var
  CurrentVersion : integer;
begin
DatenbankVersion := true;
  try
    Qry_DataVersion.SQL.Text :=
      'SELECT 1 FROM rdb$relations where rdb$relation_name = :TableName';
    Qry_DataVersion.ParamByName('TableName').AsString:= 'DBINFO';
    Qry_DataVersion.Open;

    if Qry_DataVersion.RecordCount = 0 then
      begin
        Qry_DataVersion.Close;
        Qry_DataVersion.SQL.Text :=
          'CREATE GENERATOR GEN_DBINFO_ID; ';
        Qry_DataVersion.ExecSQL;
        DM_Update.Con_UpdateConfig.Commit;
        Qry_DataVersion.SQL.Text :=
          'CREATE TABLE DBINFO (ID_INFO ID_DOM, VERSION NUMMER_DOM)';
        Qry_DataVersion.ExecSQL;
        DM_Update.Con_UpdateConfig.Commit;
        Qry_DataVersion.SQL.Text :=
          'ALTER TABLE DBINFO ADD CONSTRAINT PK_DBINFO PRIMARY KEY (ID_INFO) USING INDEX ID_INFO';
        Qry_DataVersion.ExecSQL;
        DM_Update.Con_UpdateConfig.Commit;
        Qry_DataVersion.SQL.Text :=
          'CREATE OR ALTER TRIGGER TRI_DBINFO FOR DBINFO ACTIVE BEFORE INSERT POSITION 0 '+
          'AS BEGIN '+
          'IF (NEW.ID_INFO IS NULL) THEN '+
          'NEW.ID_INFO = GEN_ID(GEN_DBINFO_ID,1);END';
        Qry_DataVersion.ExecSQL;
        DM_Update.Con_UpdateConfig.Commit;

        Qry_DataVersion.Close;
        Qry_DataVersion.SQL.Text :=
          'INSERT INTO DBINFO (VERSION)VALUES(:Bereich)';
        Qry_DataVersion.ParamByName('Bereich').Value := 1;
        Qry_DataVersion.ExecSQL;
        DM_Update.Con_UpdateConfig.Commit;
      end
    else
      begin
        CurrentVersion := 2;//Wert kann je nach Softwareversion der DB angepasst werden
        Qry_DataVersion.SQL.Text :=
          'SELECT * FROM DBINFO';
        Qry_DataVersion.Open;
        if Qry_DataVersion.FieldByName('Version').AsInteger <> CurrentVersion then
          begin
            if UpdateVersion(CurrentVersion) = true then
              begin
                Form1.ServiceMemo.Lines.Add('Datenbankupdate auf Version '+IntToStr(CurrentVersion)+
                                            ' erfolgreich durchgeführt!');
                Version := CurrentVersion;
              end
          end
        else
          Version := CurrentVersion;
      end;
  except
    DatenbankVersion := false;
  end;
end;

function TDM_Update.UpdateVersion(var Version : Integer) : Boolean;
begin
UpdateVersion := true;
  try
    Qry_UpdateVersion.SQL.Text :=
      'UPDATE DBINFO SET VERSION = :Version WHERE ID_INFO =:Id';
    Qry_UpdateVersion.ParamByName('Version').Value := Version;
    Qry_UpdateVersion.ParamByName('Id').Value := 1;
    Qry_UpdateVersion.ExecSQL;
    Con_UpdateConfig.Commit;
    case Version of
    1: begin
         UpdateDataDB(Version);//in die Case Anweisungen je nach Notwendigkeit
         UpdateUserDB(Version);
       end;
    2: begin
         UpdateDataDB(Version);//in die Case Anweisungen je nach Notwendigkeit
       end;
    end;
  except
    UpdateVersion := false;
  end;
end;

function TDM_Update.UpdateDataDB(var Version : Integer) : Boolean;
begin
  //Update der Datenbank Data
end;

function TDM_Update.UpdateUserDB(var Version : Integer) : Boolean;
begin
  //Update der Datenbank User
end;

end.
Ich hoffe das meine Gedanke ansonsten in Ordnung sind. Kommentare erwünscht.

Gruß Jens

hoika 28. Jan 2010 18:46

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Hallo,

SELECT 1 FROM rdb$relations where rdb$relation_name = :TableName

if Qry_DataVersion.RecordCount = 0

Das passt nicht !!!

Prinzipiell nie !! auf RecordCount prüfen ...

Existiert die Tabelle, wird 1 zurückgegeben -> RecordCount=1
Existiert die Tabelle nicht, wird NULL zurückgegeben -> RecordCount=1


Du musst auf nach dem Open auf Qry_DataVersion.Fields[0].AsString='1' prüfen !


Ausserdem fehlt ein Transaktions-Management,
sonst kann es passieren, die Tabelle existiert,
aber der Generator nicht.

DB.StartTransaction
try
finally
end;


Heiko

Jens Hartmann 4. Feb 2010 06:03

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Hallo hoika,

also in einem muss ich Dir leider wiedersprechen.
Zitat:

Zitat von hoika
Prinzipiell nie !! auf RecordCount prüfen ...

Existiert die Tabelle, wird 1 zurückgegeben -> RecordCount=1
Existiert die Tabelle nicht, wird NULL zurückgegeben -> RecordCount=1

Das ist nicht ganz richtig. Wenn die Tabelle nicht vorhanden ist, gibt mir Delphi ein RecordCount = 0 zurück. Ein RecordCount 1 bekomme ich nur, wenn die Tabelle bereits existiert. Also wüsste ich momentan nicht, warum das nicht funktionieren sollte. Es geht ja auch bei mir. Hat das vieleicht auch so einen Grund wie die Abfrage auf...
Delphi-Quellcode:
  if blablabla.Checked then
//
if blablabla.Checked = true then
Zitat:

Zitat von hoika
DB.StartTransaction
try
finally
end;

Das werde ich aufjedenfall noch einfügen. Wobei ich momentan am überlegen bin, ob ich nicht vieleicht grade ein kleines Update Tool schreiben sollte, was unabhängig von meinem eigendlichen Programm ist.

Gruß Jens

haentschman 4. Feb 2010 06:32

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Guten Morgen...
Zitat:

kann mir vieleicht mal jemand was zu der Metadaten Komponente sagen.
...siehe #20. Einfach auf die Form klatschen, einstellen welche Metadaten du sehen willst --> Open und du hast eine Ergebnismenge mit den Informationen. Ich habe das bisher nur lesend genutzt, ob man auch Informationen schreiben kann oder ob die Ergebnismenge nur Lesen ist kann ich nicht sagen.

:hi:

hoika 4. Feb 2010 06:34

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Hallo,

ich habe mein "Update-Tool" in eine DLL ausgelagert.
Damit kann ich es in mehreren Programm-Modulen benutzen.

Ausserdem ist eine DLL schnell aktualisiert und weggeschickt,
falls mal was internes an der DB geändert/verbessert wird,
was das eigentliche Programm nicht interessieren muss.

Mit RecordCount meinte ich, dass verschiedene DB-Komponenten
das unterschiedlich "implementieren".


Metadaten sollte mn nie direkt schreiben,
es sei denn:
- es geht nicht anders
- man weiss, was man macht

Ich teste solche Sachen zuerst per IBExpert,
dort wird der "Metadaten-Code" ja angezeigt.


Heiko

Jens Hartmann 10. Feb 2010 20:58

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Hallo zusammen,

so ich habe jetzt so eine
Delphi-Quellcode:
function
mal bearbeitet und auch versucht das mit der Transaktion und so umzusetzten. Was mit noch fehlt ist die Auswertung der Exception. Also dadurch bitte nicht verwirren lassen. Ich will nur mal hören, ob das sonst so schon besser aussieht.

Delphi-Quellcode:
//function zur Reorganisation der Datenbank aus der Stammdatenbank
procedure TForm1.Reorganisation1Click(Sender: TObject);
var
  i : integer;
  ComPortConnect : Boolean;
begin
  ComPortConnect := false;
  if MessageDlg('Achtung durch die Reorganisation werden vorhandene Daten gelöscht!'+
    'Wollen Sie die Reorganisation wirklich starten?'
    ,mtWarning,[mbYes, mbNo], 0) = mrYes then begin
  FPasswort.EDPasswort.Clear;
  FPasswort.BTOK.Enabled := false;
  case FPasswort.ShowModal of mrOK:
  begin
  if ComPort1.Connected = true then
    begin
      ComPort1.Close;
      tbConnect.Enabled := true;
      tbDisconnect.Enabled := false;
      ComPortConnect := true;
    end;
  VST.Clear;
  try
    try
      Qry_Reorganisation.SQL.Text :=
        'SELECT 1 FROM rdb$relations where rdb$relation_name = :TableName';
      Qry_Reorganisation.ParamByName('TableName').AsString:= 'MB100';
      Qry_Reorganisation.Open;

      if DropDataTableMB100 then     //function Tabelle löschen inkl. Generator und Trigger
        if CreateDataTableMB100 then //function Tabelle neu erstellen inkl. Generator und Trigger etc.
          DM_PS.ConPSSecur.Commit;   //Wenn alles OK, dann Commit als Transaktion

      except
        DM_PS.ConPSSecur.Rollback;   //Wenn Exception das Rollback
        ShowMessage('Reorganisation fehlgeschlagen');
      end;

      finally
        if InsertDataTableMB100 then
          begin
            ShowMessage('Reorganisation erfolgreich abgeschlossen');
            Servicefunktionen1.Visible := false;
            Reorganisation1.Visible := false;
            if ComPortConnect then
              tbConnect.Click;
          end;
        end;
      end;
    end;
  end;
end;

//Tabelle löschen
function TForm1.DropDataTableMB100 : Boolean;
begin
DropDataTableMB100 := true;
try
  if Qry_Reorganisation.Fields[0].AsString = '1' then
    begin
      Qry_Reorganisation.SQL.Text :=
        'DROP TRIGGER TRI_MB100';
      Qry_Reorganisation.ExecSQL;

      Qry_Reorganisation.SQL.Text :=
        'DROP SEQUENCE GEN_MB100_ID';
      Qry_Reorganisation.ExecSQL;

      Qry_Reorganisation.SQL.Text :=
        'DROP TABLE MB100';
      Qry_Reorganisation.ExecSQL;
    end;
  except
    DropDataTableMB100 := false;
  end;
end;

//Tabelle Erstellen
function TForm1.CreateDataTableMB100 : Boolean;
begin
CreateDataTableMB100 := true;
try
  Qry_Reorganisation.Close;
  Qry_Reorganisation.SQL.Text :=
    'CREATE GENERATOR GEN_MB100_ID; ';
  Qry_Reorganisation.ExecSQL;

  Qry_Reorganisation.SQL.Text :=
    'CREATE TABLE MB100 (ID ID_DOM NOT NULL, LFDNR NUMMER_DOM NOT NULL, '+
    'DATUM DATUM_DOM NOT NULL, UHRZEIT ZEIT_DOM NOT NULL, EREIGNIS TEXT_DOM, '+
    'TEILNEHMER TEXT_DOM, BEREICH TEXT_DOM, SYSTEMZEIT ZEITEN_DOM DEFAULT ''NOW'' NOT NULL)';
  Qry_Reorganisation.ExecSQL;

  Qry_Reorganisation.SQL.Text :=
    'ALTER TABLE MB100 ADD CONSTRAINT PK_MB100 PRIMARY KEY (ID) USING INDEX ID';
  Qry_Reorganisation.ExecSQL;

  Qry_Reorganisation.SQL.Text :=
    'CREATE OR ALTER TRIGGER TRI_MB100 FOR MB100 ACTIVE BEFORE INSERT POSITION 0 '+
    'AS BEGIN '+
    'IF (NEW.ID IS NULL) THEN '+
    'NEW.ID = GEN_ID(GEN_MB100_ID,1);END';
  Qry_Reorganisation.ExecSQL;
except
  CreateDataTableMB100 := false;
end;
end;

//Daten aus Stammdatenbank wieder in die neu erstellte Datenbank einfügen
function TForm1.InsertDataTableMB100 : Boolean;
var
  i : integer;
begin
InsertDataTableMB100 := true;
try
  Qry_Reorganisation.Close;
  Qry_Reorganisation.SQL.Text := 'SELECT DATA_READ_COM FROM SERVICE_TABLE';
  Qry_Reorganisation.Open;

  PBFortschritt.Position := 0;
  PBFortschritt.Max := Qry_Reorganisation.RecordCount;

  Qry_Reorganisation.First;
  for i := 0 to Qry_Reorganisation.RecordCount - 1 do
    begin
      DataMB100 := Qry_Reorganisation.FieldByName('DATA_READ_COM').AsString;
      DatenverarbeitungVSTMB100;
      PBFortschritt.Position := Qry_Reorganisation.RecNo;
      Qry_Reorganisation.Next;
      Application.ProcessMessages;
    end;
  PBFortschritt.Position := 0;
except
  InsertDataTableMB100 := false;
end;
end;
Über Eure Anregungen bin ich dankbar.

Gruß Jens

hoika 11. Feb 2010 07:20

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Hallo,

ein paar Anmerkungen

1.
Ich mache das immer so

Delphi-Quellcode:
function CreateDataTableMB100: Boolean;
begin
  Result:= False;

  try
    // create code

    Result:= True;

  except
    // Ausnahme-Behandlung
  end;
end;
2.
Create Or Alter Trigger

Warum Alter, der Trigger ist doch gelöscht.
Aber OK, neue Syntax darf man auch nutzen.

3.
Den Primary Key würde ich gleich an das Create Table packen.

SQL-Code:
Create Table XXX (Id Integer, Name Char(20), primary key(id))
Dabei wird allerdings ein RDBXXX Index angelegt, was nicht so schön aussieht,
per Using könnte man eine anderen (unique) Index festlegen.


4. Domains
Warum schreibst du das Not Null noch dahinter ?
Ich bin mir jetzt nicht ganz scher,
aber kann man das bei der Domain selber nicht schon hinschreiben ?


Das wars ;)


Heiko

Jens Hartmann 11. Feb 2010 08:26

Re: Create Table mit Firebird und ZEOS, wie richtig machen
 
Hallo,

danke schon mal für die Anregungen.
Delphi-Quellcode:
function CreateDataTableMB100: Boolean;
begin
  Result:= False;

  try
    // create code

    Result:= True;

  except
    // Ausnahme-Behandlung
  end;
end;
Ja, scheint mir logisch zu sein.
Zitat:

Zitat von hoika
Warum schreibst du das Not Null noch dahinter ?

Ja, da hast Du recht. Habe ich nicht dran gedacht.

Gruß Jens


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