|
![]() |
Registriert seit: 22. Feb 2017 990 Beiträge |
#1
Datenbank: MariaDB • Version: 11.5.2 • Zugriff über: Zeos 8.0.0
Hi,
ich wollte mal so in die Runde fragen, wie ihr jeweils so die Datenbank beim Kunden aktuell haltet. Im Zuge der Weiterentwicklung eines Projekts, kommen ja die einen oder anderen Tabellen bzw. Felder in den Tabellen hinzu, oder man ändert auch mal die Feldgrößen. In der Entwicklungsdatenbank ja keine Problem, jedoch müssen die Änderungen auch zu Kunden übermittelt werden. In einem älteren Projekt (mysql) habe ich das mal so gemacht, dass ich eine Klasse hatte, die die gesamte Datenbankstruktur abgebildet hat, jedes Feld und jede Tabelle überprüft und ggf. aktualisiert hat. Das hat seinerzeit auch recht gut geklappt. Jetzt unter MariaDB habe ich das Problem, z.B bei den DECIMAL(10,2) Felder vernüftig an die Größe zu kommen (Sicherlich mein Fehler). Zeos liefert mir den DataType ftFmtBCD zurück, und ich hab noch nicht so ganz raus, wie ich da vernüftig an die Größe kommen. Zwar liefert mir ein in mariadb DECIMAL(10,2) die 2 in Size für die Nachkommastellen, aber wie ich an die 10 komme, da such ich noch. Aber man könnte ja auch jede DB-Änderung als ALTER TABLE SQL-Zeile speichern und beim Kunden dann abspulen. Ist nur blöd, wenn da mal eine zwischen vergessen wurde. Auch müsste man für die Datenbank eine Version führen, damit die DB soweit aktualisiert wird, auch wenn der Kunde mal ein Update verpasst hat. Oder könnte man auch ein Script in SQL machen mit Zeilen wie CREATE TABLE IF NOT EXISTS 'blaba' .... ELSE ALTER TABLE 'blabla'... ? (Weiß nicht ob das so geht) Ich bin mir noch nicht so ganz klar, wie ich es jetzt machen will, damit es später mir möglichst wenig aufwand relativ fehlerfrei funktioniert.
Gruß Hobbycoder
Alle sagten: "Das geht nicht.". Dann kam einer, der wusste das nicht, und hat's einfach gemacht. |
![]() |
Registriert seit: 11. Okt 2003 Ort: Elbflorenz 44.285 Beiträge Delphi 12 Athens |
#2
Es gibt Milliarden Wege und Möglichkeiten.
So gibt es Diff-Tools für Datenbanken, welche die Strukturen abgleichen. Bei uns wurden ursprünglich Updatescripte im Setup mitgegeben. Jetzt liegen die Scripte in einer Tabelle, welche online von einem DB-Server runtergeladen werden. (mit Versionsnummer und einer optionalen Kunden-Kennung) Dann wird, entsprechend der aktuellen Programm-Version, ein Versionssetting in der Datenbank hochgesetzt (optional, beim Download, wenn ProgrammVersion neuer als die DBVersion) und dann werden der Reihe nach die DBUpdates bis zur aktuellen Version (laut Setting) ausgeführt. Ist aber auch ein Kampf, die DBUpdates und das Erstellungsscript (für neue Datenbanken) synchron zu halten. Es geht aber nicht nur im die Tabellen-Struktur, Trigger, StoredProcs, sondern auch um geänderte/neue/alte Daten (INSERT/UPDATE/DELETE).
Ein Therapeut entspricht 1024 Gigapeut.
|
![]() |
Registriert seit: 3. Mär 2014 Ort: Berlin 450 Beiträge Delphi 12 Athens |
#3
Aber man könnte ja auch jede DB-Änderung als ALTER TABLE SQL-Zeile speichern und beim Kunden dann abspulen. Ist nur blöd, wenn da mal eine zwischen vergessen wurde. Auch müsste man für die Datenbank eine Version führen, damit die DB soweit aktualisiert wird, auch wenn der Kunde mal ein Update verpasst hat.
|
![]() |
Registriert seit: 24. Mai 2017 Ort: Wien, Österreich 1.237 Beiträge Delphi 12 Athens |
#4
Für mich hat sich bewährt:
- Im Programm gibt es eine Constante DBVersion. Das ist die Version, die das Programm von der Datenbank voraussetzt. - In der Datenbank gibt es (in einer Tabelle) ebenfalls eine DBVersion, das ist die Version, die die DB tatsächlich hat. Bei Abweichung: Fehlermeldung. - Beim Programmstart führt das Programm eine Reihe von solchen Anweisungen aus:
Code:
Ist die Version lt. DB kleiner als 257 wird das ausgeführt, sonst nicht.
Result := Result and DoVersion(nDBVersion, 257, 'ALTER TABLE TBLMATERIAL alter column ' + 'zus_beschreibung nvarchar(max);',
'Zusatzfelder für Entwicklung II'); - Bei Erfolg wird die version in der DB angepasst usw - Weitere Änderungen werden einfach angefügt. - Das gleiche Schema gibt es BTW auch für Dateninhalte. Nebennutzen: Da nicht alle wollen, dass die App Änderungen an der DB selber macht, kann man die SQL-Scripts in eine Datei ausgeben lassen, die dann gesondert ausgeführt wird. Auslassen von Versionsprüngen gibt es damit nicht. Wenn eine Änderung fehlt schlägt fällt es auch sofort auch. Und über den Text bei den Änderungen ergibt sich automatisch eine History/Doku.
Certified Delphi Developer (2025)
|
![]() |
Registriert seit: 19. Okt 2003 Ort: Heilbronn 684 Beiträge Delphi 10.4 Sydney |
#5
Ich hatte es damals für Firebird so gebaut (im Moment bin ich in der aktuellen Firma nicht für DB Updates zuständig) :
DB hat Version und Unterversion. Version muss mit der im Programm hinterlegten Version übereinstimmen. Unterversion gibt den Schritt im Updateverlauf an. Ein Schritt konnte das Hinzufügen eines Feldes sein, das Eintragen von neuen Konstanten in eine Tabelle, das Transformieren von Daten über ein "EXECUTE BLOCK" etc. Vorteil war natürlich, dass ich für jeden Vorgang eine spezifische Fehlermeldung hatte, wenn was schief ging und diese speichern und melden konnte, so konnte der Support sich mit dem Kunden pro-aktiv in Verbindung setzen und den Fehler beheben und das Update neu laufen lassen. Dazu habe ich 2 Tools geschrieben, 1 um die XML Dateien zu erstellen, die die einzelnen Befehle beinhalten und das andere lief beim Kunden, zeigte alle dort registrierten Datenbanken an und in welcher Version diese sind. Dort über Checkbox kurz ausgewählt, welche aktualisiert werden sollen und los ging es ![]() |
![]() |
Registriert seit: 6. Mär 2007 Ort: Osnabrück 613 Beiträge Delphi XE6 Enterprise |
#6
Jede Datenbank hat virtuelle Tabellen mit Metadaten, aus denen man entnehmen kann, wie die Datenbank aufgebaut ist, wie die Tabellen heißen, welche Felder sie haben, welche Typen die haben usw. Die musst Du einfach abfragen, so bekommst Du die benötigten Infos.
Siehe ![]() |
![]() |
Registriert seit: 11. Okt 2003 Ort: Elbflorenz 44.285 Beiträge Delphi 12 Athens |
#7
Ach ja, bezüglich der AppVersion und DBVersion,
denn es kann ja auch vorkommen, dass * man mit unterschiedlichen ProgrammVersionen auf die selbe DB zugreift * oder mit einem Programm auf unterschiedliche Datenbanken. Für bestimmte Dinge, im Programm, benötigt es eine gewisse DB-Version, aber für gewisse Funktionen/Strukturen/Daten, benötigt es eine gewisse Programm-Version. (Minimal-Version und Maximal-Version) Die Anwendung setzt also voraus, dass die DB eine bestimmte (die gleiche) Version besitzt, bzw. in einem vorgegebenen Versionsbereich vorliegt. Und/oder andersrum, eine bestimmte DB-Version setzt eine Anwendung vor, welche in einem gewissenen Versionsbereich liegt.
Ein Therapeut entspricht 1024 Gigapeut.
Geändert von himitsu (11. Feb 2025 um 11:32 Uhr) |
![]() |
Registriert seit: 24. Mai 2017 Ort: Wien, Österreich 1.237 Beiträge Delphi 12 Athens |
#8
Nachtrag: Wenn man TMS Aurelius als ORM verwendet, dann zieht das ORM die DB automatisch mit.
Certified Delphi Developer (2025)
|
![]() |
Registriert seit: 22. Feb 2017 990 Beiträge |
#9
Danke für die zahlreichen Inspirationen/Informationen.
Jede Datenbank hat virtuelle Tabellen mit Metadaten, aus denen man entnehmen kann, wie die Datenbank aufgebaut ist, wie die Tabellen heißen, welche Felder sie haben, welche Typen die haben usw. Die musst Du einfach abfragen, so bekommst Du die benötigten Infos.
Siehe ![]() - Neue Tabellen zur erzeugen - Weggefallene Tabellen zu löschen - Neue Columns hinzufügen - Weggefallene Columns zu entfernen - Datetype und Länge der Columns überprüfen und anpassen - Defaultwert der Columns überprüfen und anpassen Das konnte ich jetzt mit eine kleine Klasse erledigen, die ich hier mal reinsetze falls das mal irgendwer gebrauchen kann.
Delphi-Quellcode:
Aufruf:
unit uTestTables2;
interface uses System.Classes, System.SysUtils, ZConnection, ZDataset, Data.DB, System.Generics.Collections, uRWStream; type TModifyFlag=(mfNoChanges, mfAdd, mfModify, mfDelete); TColumnModifyFlag=(cmfNone, cmfDatatype, cmfDefaultValue); TDBColumn=class private FName: string; FColumnDefault: string; FColumnType: string; FModifyFlag: TModifyFlag; FColumnModifyFlag: TColumnModifyFlag; procedure SetColumnDefault(const Value: string); procedure SetColumnType(const Value: string); procedure SetName(const Value: string); procedure SetModifyFlag(const Value: TModifyFlag); procedure SetColumnModifyFlag(const Value: TColumnModifyFlag); public constructor Create; procedure WriteToStream(st: TStream); procedure ReadFromStream(st: TStream; Version: Integer); procedure Compare(Source: TObject); procedure Assign(Source: TObject); function GetDefault: string; published property Name: string read FName write SetName; property ColumnType: string read FColumnType write SetColumnType; property ColumnDefault: string read FColumnDefault write SetColumnDefault; property ModifyFlag: TModifyFlag read FModifyFlag write SetModifyFlag; property ColumnModifyFlag: TColumnModifyFlag read FColumnModifyFlag write SetColumnModifyFlag; end; TDBTable=class(TObjectList<TDBColumn>) private FName: string; FCollation: string; FModifyFlag: TModifyFlag; procedure SetCollation(const Value: string); procedure SetName(const Value: string); procedure SetModifyFlag(const Value: TModifyFlag); public procedure WriteToStream(st: TStream); procedure ReadFromStream(st: TStream; Version: Integer); procedure Compare(Source: TObject); function GetColumnByName(value: string): TDBColumn; procedure Assign(Source: TObject); published property Name: string read FName write SetName; property Collation: string read FCollation write SetCollation; property ModifyFlag: TModifyFlag read FModifyFlag write SetModifyFlag; end; TDBDatabase=class(TObjectList<TDBTable>) private FFilename: string; FSchemaName: string; FCollation: string; procedure SetCollation(const Value: string); procedure SetSchemaName(const Value: string); function GetSchema(Con: TZConnection; Schema: string): Boolean; procedure GetTables(Con: TZConnection; Schema: string); procedure GetColumns(Con: TZConnection; Schema: string; TT: TDBTable); public procedure Compare(Source: TObject); procedure BuildFromDB(Con: TZConnection; RootPass: string; Schema: string); procedure LoadFromFile(Filename: string = ''); procedure SaveToFile(Filename: string = ''); function GetTableByName(value: string): TDBTable; function IsModified: Boolean; function CreateTableScript(Script: TStrings): Boolean; function ExecSQLLine(Con: TZConnection; Line: string): Boolean; published property SchemaName: string read FSchemaName write SetSchemaName; property Collation: string read FCollation write SetCollation; end; Const FileVersion = 1; StringSeparator = '`'; implementation { TDBColumn } procedure TDBColumn.Assign(Source: TObject); var TC: TDBColumn; begin if Source is TDBColumn then begin TC:=TDBColumn(Source); self.FName:=TC.Name; self.FColumnType:=TC.ColumnType; self.FColumnDefault:=TC.ColumnDefault; end; end; procedure TDBColumn.Compare(Source: TObject); var TC: TDBColumn; begin Self.FModifyFlag:=mfNoChanges; if Source is TDBColumn then begin TC:=TDBColumn(Source); if (self.FColumnDefault<>TC.ColumnDefault) then begin Self.FModifyFlag:=mfModify; self.FColumnModifyFlag:=cmfDefaultValue; self.FColumnDefault:=TC.ColumnDefault; end; if (self.FColumnType<>TC.ColumnType) then begin Self.FModifyFlag:=mfModify; self.FColumnModifyFlag:=cmfDatatype; self.FColumnType:=TC.ColumnType; end; end; end; constructor TDBColumn.Create; begin inherited; Self.FColumnModifyFlag:=cmfNone; end; function TDBColumn.GetDefault: string; begin if self.FColumnDefault<>'NULL' then Result:=''''+self.FColumnDefault+'''' else Result:=Self.FColumnDefault; end; procedure TDBColumn.ReadFromStream(st: TStream; Version: Integer); begin if st<>nil then begin self.FName:=ReadStrFromStream(st); self.FColumnType:=ReadStrFromStream(st); self.FColumnDefault:=ReadStrFromStream(st); end; end; procedure TDBColumn.SetColumnDefault(const Value: string); begin FColumnDefault := Value; end; procedure TDBColumn.SetColumnModifyFlag(const Value: TColumnModifyFlag); begin FColumnModifyFlag := Value; end; procedure TDBColumn.SetColumnType(const Value: string); begin FColumnType := Value; end; procedure TDBColumn.SetModifyFlag(const Value: TModifyFlag); begin FModifyFlag := Value; end; procedure TDBColumn.SetName(const Value: string); begin FName := Value; end; procedure TDBColumn.WriteToStream(st: TStream); begin if st<>nil then begin WriteStrToStream(st, self.FName); WriteStrToStream(st, self.FColumnType); WriteStrToStream(st, self.FColumnDefault); end; end; { TDBTable } procedure TDBTable.Assign(Source: TObject); var TT: TDBTable; TC: TDBColumn; I: Integer; begin if Source is TDBTable then begin TT:=TDBTable(Source); self.FName:=TT.Name; self.FCollation:=TT.Collation; self.Clear; for I := 0 to TT.Count-1 do begin TC:=TDBColumn.Create; TC.Assign(TT[i]); TC.ModifyFlag:=mfAdd; self.Add(TC); end; end; end; procedure TDBTable.Compare(Source: TObject); var TT: TDBTable; TC, TC2: TDBColumn; I: Integer; begin if Source is TDBTable then begin TT:=TDBTable(Source); for I := 0 to Self.Count-1 do begin TC:=TT.GetColumnByName(self[i].Name); if TC<>nil then self[i].Compare(TC) else self[i].ModifyFlag:=mfDelete; if self[i].ModifyFlag<>mfNoChanges then self.FModifyFlag:=mfModify; end; for I := 0 to TT.Count-1 do begin TC:=self.GetColumnByName(TT[i].Name); if TC=nil then begin TC2:=TDBColumn.Create; TC2.Assign(TC); TC2.ModifyFlag:=mfAdd; self.Add(TC2); self.ModifyFlag:=mfModify; end; end; end; end; function TDBTable.GetColumnByName(value: string): TDBColumn; var I: Integer; begin Result:=nil; for I := 0 to Self.Count-1 do if self[i].Name.ToLower=value.ToLower then begin Result:=self[i]; Break; end; end; procedure TDBTable.ReadFromStream(st: TStream; Version: Integer); var TC: TDBColumn; I, C: Integer; begin if st<>nil then begin Self.Clear; self.FName:=ReadStrFromStream(st); self.FCollation:=ReadStrFromStream(st); C:=ReadIntFromStream(st); for I := 0 to C-1 do begin TC:=TDBColumn.Create; TC.ReadFromStream(st, Version); self.Add(TC); end; end; end; procedure TDBTable.SetCollation(const Value: string); begin FCollation := Value; end; procedure TDBTable.SetModifyFlag(const Value: TModifyFlag); begin FModifyFlag := Value; end; procedure TDBTable.SetName(const Value: string); begin FName := Value; end; procedure TDBTable.WriteToStream(st: TStream); var I: Integer; begin if st<>nil then begin WriteStrToStream(st, self.FName); WriteStrToStream(st, self.FCollation); WriteIntToStream(st, self.Count); for I := 0 to self.Count-1 do self[i].WriteToStream(st); end; end; { TDBDatabase } procedure TDBDatabase.BuildFromDB(Con: TZConnection; RootPass: string; Schema: string); var FCon: TZConnection; FQ: TZQuery; begin FCon:=TZConnection.Create(nil); try FCon.HostName:=Con.HostName; FCon.Port:=Con.Port; FCon.User:='root'; Fcon.Password:=RootPass; Fcon.Database:='information_schema'; Fcon.Protocol:=Con.Protocol; Fcon.LibraryLocation:=Con.LibraryLocation; Fcon.LibLocation:=Con.LibLocation; try FCon.Connect; if FCon.Connected then begin self.Clear; self.FSchemaName:=''; self.FCollation:=''; if self.GetSchema(FCon, Schema) then begin Self.GetTables(FCon, Schema); end; end; except end; finally FCon.Free; end; end; procedure TDBDatabase.Compare(Source: TObject); var DB: TDBDatabase; TT, TT2: TDBTable; I: Integer; begin if Source is TDBDatabase then begin DB:=TDBDatabase(Source); for I := 0 to self.Count-1 do begin TT:=DB.GetTableByName(self[i].Name); if TT<>nil then self[i].Compare(TT) else self[i].ModifyFlag:=mfDelete; end; for i:=0 to db.Count-1 do begin TT:=self.GetTableByName(DB[i].Name); if TT=nil then begin TT2:=TDBTable.Create(True); TT2.Assign(DB[i]); TT2.ModifyFlag:=mfAdd; self.Add(TT2); end; end; end; end; function TDBDatabase.CreateTableScript(Script: TStrings): Boolean; var s: string; I: Integer; C: Integer; begin Script.Clear; Result:=False; try Script.Add('USE '+StringSeparator+self.SchemaName+StringSeparator+';'); for I := 0 to self.Count-1 do begin case self[i].ModifyFlag of mfAdd: begin s:='CREATE TABLE '+StringSeparator+self[i].Name+StringSeparator+' ('; for C := 0 to self[i].Count-1 do begin s:=s+StringSeparator+self[i][C].Name+StringSeparator+' '+self[i][c].ColumnType+' DEFAULT '+self[i][c].ColumnDefault+' ,'; end; s:=Copy(s, 1, Length(s)-2); s:=s+') COLLATE='''+self[i].Collation+''';'; Script.Add(S); end; mfModify: begin for C := 0 to self[i].Count-1 do case self[i][c].ModifyFlag of mfModify: begin s:='ALTER TABLE '+StringSeparator+self[i].Name+StringSeparator+' CHANGE COLUMN '+StringSeparator+self[i][C].Name+StringSeparator+' '+StringSeparator+self[i][C].Name+StringSeparator+' '+self[i][c].ColumnType+' DEFAULT '+self[i][c].GetDefault+';'; Script.Add(s); end; mfAdd: begin s:='ALTER TABLE '+StringSeparator+self[i].Name+StringSeparator+' ADD COLUMN '+StringSeparator+self[i][C].Name+StringSeparator+' '+self[i][c].ColumnType+' DEFAULT '+self[i][c].GetDefault+';'; Script.Add(s); end; mfDelete: begin s:='ALTER TABLE '+StringSeparator+self[i].Name+StringSeparator+' DROP COLUMN '+StringSeparator+self[i][C].Name+StringSeparator+';'; Script.Add(s); end; end; end; mfDelete: begin s:='DROP TABLE '+StringSeparator+self[i].Name+StringSeparator+';'; Script.Add(s); end; end; end; Result:=True; finally end; end; function TDBDatabase.ExecSQLLine(Con: TZConnection; Line: string): Boolean; var q: TZQuery; begin Result:=False; q:=TZQuery.Create(nil); try q.Connection:=Con; q.SQL.Text:=Line; q.ExecSQL; Result:=True; finally q.Free; end; end; procedure TDBDatabase.GetColumns(Con: TZConnection; Schema: string; TT: TDBTable); var q: TZQuery; TC: TDBColumn; begin q:=TZQuery.Create(nil); try q.Connection:=Con; q.SQL.Text:='Select * from COLUMNS where TABLE_SCHEMA=:schema and TABLE_NAME=:tablename order by ORDINAL_POSITION'; q.Params.ParamValues['schema']:=Schema; q.Params.ParamValues['tablename']:=TT.Name; q.Active:=True; while not q.Eof do begin TC:=TDBColumn.Create; TT.Add(TC); TC.Name:=q.FieldByName('COLUMN_NAME').AsString; TC.ColumnType:=q.FieldByName('COLUMN_TYPE').AsString; TC.FColumnDefault:=q.FieldByName('COLUMN_DEFAULT').AsString; q.Next; end; q.Active:=False; finally q.Free; end; end; function TDBDatabase.GetSchema(Con: TZConnection; Schema: string): Boolean; var q: TZQuery; begin Result:=False; q:=TZQuery.Create(nil); try q.Connection:=Con; q.SQL.Text:='Select * from SCHEMATA where SCHEMA_NAME=:schema'; q.Params.ParamValues['schema']:=Schema; q.Active:=True; if q.RecordCount>0 then begin self.FSchemaName:=q.FieldByName('SCHEMA_NAME').AsString; self.FCollation:=q.FieldByName('DEFAULT_COLLATION_NAME').AsString; Result:=True; end; q.Active:=False; finally q.Free; end; end; function TDBDatabase.GetTableByName(value: string): TDBTable; var I: Integer; begin Result:=nil; for I := 0 to Self.Count-1 do if self[i].Name.ToLower=value.ToLower then begin Result:=self[i]; Break; end; end; procedure TDBDatabase.GetTables(Con: TZConnection; Schema: string); var q: TZQuery; TT: TDBTable; TC: TDBColumn; begin q:=TZQuery.Create(nil); try q.Connection:=Con; q.SQL.Text:='Select * from TABLES where TABLE_SCHEMA=:schema order by TABLE_NAME'; q.Params.ParamValues['schema']:=Schema; q.Active:=True; while not q.Eof do begin TT:=TDBTable.Create(True); self.Add(TT); TT.Name:=q.FieldByName('TABLE_NAME').AsString; TT.Collation:=q.FieldByName('TABLE_COLLATION').AsString; GetColumns(Con, Schema, TT); q.Next; end; q.Active:=False; finally q.Free; end; end; function TDBDatabase.IsModified: Boolean; var I: Integer; begin Result:=False; for I := 0 to self.Count-1 do if self[i].ModifyFlag<>mfNoChanges then begin Result:=True; Break; end; end; procedure TDBDatabase.LoadFromFile(Filename: string); var st: TFileStream; Version: Integer; I, C: Integer; TT: TDBTable; begin if Filename<>'' then FFilename:=Filename; if FileExists(FFilename) then begin Self.Clear; self.FSchemaName:=''; self.FCollation:=''; st:=TFileStream.Create(FFilename, fmOpenRead); if st<>nil then try Version:=ReadIntFromStream(st); self.FSchemaName:=ReadStrFromStream(st); self.FCollation:=ReadStrFromStream(st); C:=ReadIntFromStream(st); for I := 0 to C-1 do begin TT:=TDBTable.Create(True); TT.ReadFromStream(st, Version); self.Add(TT); end; finally st.Free; end; end; end; procedure TDBDatabase.SaveToFile(Filename: string); var st: TFileStream; I: Integer; begin if Filename<>'' then FFilename:=Filename; if DirectoryExists(ExtractFilePath(FFilename)) then begin st:=TFileStream.Create(FFilename, fmCreate); if st<>nil then try WriteIntToStream(st, FileVersion); WriteStrToStream(st, self.FSchemaName); WriteStrToStream(st, self.FCollation); WriteIntToStream(st, self.Count); for I := 0 to self.Count-1 do self[i].WriteToStream(st); finally st.Free; end; end; end; procedure TDBDatabase.SetCollation(const Value: string); begin FCollation := Value; end; procedure TDBDatabase.SetSchemaName(const Value: string); begin FSchemaName := Value; end; end.
Delphi-Quellcode:
Die Proceduren LoadFromFile, SaveToFile, ReadFromStream und WriteToStream muss man zum Testen rausschmeißen.
var
DB, DB2: TDBDatabase; sl: TStringList; I: Integer; q: TZQuery; begin DB:=TDBDatabase.Create(True); DB2:=TDBDatabase.Create(True); sl:=TStringList.Create; try if ExtactDBResource then begin DB.BuildFromDB(con1, '123456', 'testschema'); //Hier muss das Root-Passwort der DB verwendet werden. DB2.LoadFromFile(ExtractFilePath(Application.ExeName)+'testschema.shdat'); DB.Compare(DB2); if DB.IsModified then begin if DB.CreateTableScript(sl) then begin if sl.Count>1 then begin for I := 1 to sl.Count-1 do begin DB.ExecSQLLine(con1, sl[i]); end; end; end; end; end; finally DB.Free; DB2.Free; sl.Free; end; Wer die dafür notwendige Unit haben möchte, kann mich ja anschreiben. Und wer nicht ZEOS verwendet, muss das für seine vewendete DB-Komponenten anpassen. Das ganze ist natürlich recht einfach gehalten, weil es mir ja nur um die o.g. Tabellen- und Feldeigenschaften geht. Wer mehr will, kann das ja entsprechend anpassen.
Gruß Hobbycoder
Alle sagten: "Das geht nicht.". Dann kam einer, der wusste das nicht, und hat's einfach gemacht. |
![]() |
Registriert seit: 24. Mai 2017 Ort: Wien, Österreich 1.237 Beiträge Delphi 12 Athens |
#10
Wow. Das ist ja eine Kanone für Spatzen. Ich weiß nicht. Änderungen an der Db ziehen oft Änderungen an den Daten nach sich. Manchmal werden Felder umbenannt + der Inhalt darf aber nicht verloren gehen. Ebenso wenn sich der Typ eienes Feldes ändert. Manche Änderungen können nur gemcht werden, wenn Constraints/Indeces/Trigger uä deaktiviert und danach aktiviert werden. Das zu Automatisieren scheint mir schwierig zu sein.
Wie gesagt, ich bin mit sowas völlig zufrieden, weil ich ja selber weiß, was sich ändern muss.
Code:
Result := Result and DoVersion(nVersion, 16, 'ALTER TABLE TBLMATERIAL DROP COLUMN BIO; ALTER TABLE TBLMATERIAL ADD BIO T_CHAR NULL',
'Spalte Bio in der Tabelle Material erstellen ...'); Result := Result and DoVersion(nVersion, 17, 'ALTER TABLE TBLMATERIAL ALTER COLUMN QUIDTEXT T_LONGTEXT', 'Die Grösse der Spalte Quidtext in der Tabelle Material wird erhöht ...'); Result := Result and DoVersion(nVersion, 18, 'ALTER TABLE TBLMATERIAL ADD LOSGROESSE T_INTEGER DEFAULT 1', 'Bei den Materialien kann eine Losgröße hinterlegt werden ...'); Result := Result and DoVersion(nVersion, 19, 'UPDATE TBLMATERIAL SET LOSGROESSE= 1', 'Losgröße auf 1 setzen ...'); Result := Result and DoVersion(nVersion, 20, 'ALTER TABLE TBLMATERIAL ADD BIOZUTATEN T_TEXT;', 'Feld für Biozutaten ergänzen ...'); Result := Result and DoVersion(nVersion, 21, 'ALTER TABLE TBLSPEISEPLAN ADD MENU T_CODE;', 'Feld für Menü ergänzen ...'); Result := Result and DoVersion(nVersion, 22, 'ALTER TABLE TBLMATERIAL ADD ZL_TAGS T_TEXT;' + 'ALTER TABLE TBLZUTAT ADD ZL_PRO_BT T_BOOLEAN;', 'Materialstamm TAGS ergänzen ...'); s := GetSQLResult('SELECT name FROM sysobjects with (nolock) WHERE (name LIKE ''%LOS%'')'); if (Trim(s) <> '') then begin Result := Result and DoVersion(nVersion, 23, 'ALTER TABLE TBLMATERIAL DROP CONSTRAINT ' + s, 'Andert die Spalte Lossgröße in der Materialien ...'); Result := Result and DoVersion(nVersion, 23, 'ALTER TABLE TBLMATERIAL ALTER COLUMN LOSGROESSE T_FLOAT', 'Andert die Spalte Lossgröße in der Materialien ...'); end;
Certified Delphi Developer (2025)
|
![]() |
Ansicht |
![]() |
![]() |
![]() |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
![]() |
![]() |