Hallo Volker,
noch ein Letztes:
Es war mir bisher auch nur über IB-Expert möglich, Deine SP in die DB zu bringen.
Per SQL gelang mir das nicht.
Ich vermute mal, wegen der vielen Hochkommas, die ich wohl nicht korrekt
maskiert bekomme.
Ansonsten, seitdem ich endlich kapiert habe, wo ich welche Informationen
aus den FB-System-Tabellen auslesen kann und wie der FB-Server auf bestimmte
Aktionen reagiert, habe ich mir ein eigenes Admin-Tool gebastelt, dass mir viele
Dinge einfach automatisch abnimmt, was ein Third-Party-Tool kaum leisten kann.
Eines von mehreren Beispielen:
Wenn ich in eine Tabelle, mit Bestandsdaten, eine neue Spalte anlege, die einen
Default-Wert haben soll, legt mein Tool die Spalte immer erst als "NOT NULL" an,
kopiert danach die Spalte einmal auf sich selbst und löscht danach das "NOT NULL"-Flag.
Vorteil: Der FireBird-Server setzt in den Bestands-Datensätzen automatisch
den Default-Wert in die Spalte, ohne weiteren Aufwand.
Gruss
Hamburgo
Kopieren von Daten von einer DB in eine andere DB
Moderator: thorben.braun
Hallo Volker,
so, nun habe ich das mal mit den DB-Aliases versucht.
1. Ergebnis unter FB 2.5:
a. Ich bekomme keine Fehler-Meldung mehr.
b. Es werden aber leider keine Daten (hier 1 Daten-Satz) kopiert.
Was genau habe ich gemacht:
a. In die aliases.conf habe ich eingetragen:
c. Das SQL-Statement gemäß Deiner Vorgabe angepasst:
d. Mich per PHP via PDO-Treiber mit folgendem Connect-String verbunden:
Wie auch bei den Test's zuvor habe ich zur Kontrolle die System-Tabellen
auf die Existens Deiner SP abgefragt und auch diesmal wurde sie gefunden.
Zusätzlich habe ich den betreffenden Daten-Satz aus der Quell-DB gelesen
und auch der wurde per DB-Alias gefunden.
Das ist für mich die Bestätigung, dass die DB-Aliases funktionieren.
Was kann ich nun noch tun ?
so, nun habe ich das mal mit den DB-Aliases versucht.
1. Ergebnis unter FB 2.5:
a. Ich bekomme keine Fehler-Meldung mehr.

b. Es werden aber leider keine Daten (hier 1 Daten-Satz) kopiert.

Was genau habe ich gemacht:
a. In die aliases.conf habe ich eingetragen:
b. Mit IB-Expert sowohl für die Quell-DB "Labor.FDB" als auch für die Ziel-DB "Labor_Update.FDB" für den Benutzer SYSDBA das Passwort via Bentzer-Manager gesetzt.labor = E:\DataBase\Labor.FDB
labor_update = E:\DataBase\Labor_Update.FDB
c. Das SQL-Statement gemäß Deiner Vorgabe angepasst:
Code: Alles auswählen
select * from get_xdb_insertsql('labor', 'select * from system', 17, 'system')
e. das SQL-Statement, wie unter c. gezeigt, commited.Labor_Update, SYSDBA, HomePassword
Wie auch bei den Test's zuvor habe ich zur Kontrolle die System-Tabellen
auf die Existens Deiner SP abgefragt und auch diesmal wurde sie gefunden.
Zusätzlich habe ich den betreffenden Daten-Satz aus der Quell-DB gelesen
und auch der wurde per DB-Alias gefunden.
Das ist für mich die Bestätigung, dass die DB-Aliases funktionieren.
Was kann ich nun noch tun ?
Hallo Hamburgo,
lass mal bitte die php-Ebene aus dem Spiel, das bringt bei der Analyse, ob etwas fehlt/falsch ist, nur unnötig Komplexität ins Spiel. Das Kopieren funktioniert bereits rein auf DB-Ebene.
- verwende die Aliase in IBExpert mal zur Definition der Connections, und connecte dann in IBE, dann siehst Du, ob sie funktionieren
- Du hast in IBE, wenn Du zu einer DB connectet bist, auch eine Liste mit Stored Procedures, da ist dann die SP gelistet, Du brauchst die nicht in Systemtabellen abzufragen, das macht IBE schon.
- Das select * from get_xdb_insertsql('labor', 'select * from system', 17, 'system') erzeugt einen execute block, es kopiert selber noch keine Daten.
- Diesen execute block führe mal in IBE in einem SQL-Editor aus. Dann wird kopiert
Wenn das alles passt, kannst Du php ins Spiel bringen.
Grüße, Volker
lass mal bitte die php-Ebene aus dem Spiel, das bringt bei der Analyse, ob etwas fehlt/falsch ist, nur unnötig Komplexität ins Spiel. Das Kopieren funktioniert bereits rein auf DB-Ebene.
- verwende die Aliase in IBExpert mal zur Definition der Connections, und connecte dann in IBE, dann siehst Du, ob sie funktionieren
- Du hast in IBE, wenn Du zu einer DB connectet bist, auch eine Liste mit Stored Procedures, da ist dann die SP gelistet, Du brauchst die nicht in Systemtabellen abzufragen, das macht IBE schon.
- Das select * from get_xdb_insertsql('labor', 'select * from system', 17, 'system') erzeugt einen execute block, es kopiert selber noch keine Daten.
- Diesen execute block führe mal in IBE in einem SQL-Editor aus. Dann wird kopiert
Wenn das alles passt, kannst Du php ins Spiel bringen.
Grüße, Volker
Hallo Volker,
so, ich habe das mal so gemacht, wie es vorgeschlagen hast.
Diesen Execute-Block habe ich erhalten:
Leider habe ich wieder einen Fehler erhalten. Warum ist mir ein Rätzel.
Der String, über den er meckert steht in der Spalte ""SCRIPT_USER_NR"
und ist eigentlich viel zu kurz, um einen Overflow zu produzieren.
Auch braucht er eigentlich keine Data-Conversersion, da Source und Ziel-
Tabelle absolut gleich sind.
Vielleicht findest Du ja den Grund in den 3 Bildern.
Die Tabelle hat nur 1 Datensatz.
Danke und Gruss
so, ich habe das mal so gemacht, wie es vorgeschlagen hast.
Diesen Execute-Block habe ich erhalten:
Code: Alles auswählen
execute block RETURNS (result integer, SQL varchar(30000))
as
declare declares varchar(10000);
declare params varchar(3000);
declare flds varchar(6000);
declare wildcards varchar(3000);
declare insertsql varchar(20000);
declare dstfldcount integer;
declare crlf varchar(2);
begin
-- daten aus srcSQL nach dsttabname laden
crlf = ascii_char(13) || ascii_char(10);
-- anzahl der zieltabellenfelder ermitteln
dstfldcount = (select count(rdb$field_position)
from rdb$relation_fields
where trim(rdb$relation_name) = 'SYSTEM');
-- struktur der zieltabelle ermitteln
with
a (fldname, fldpos) as (
select trim(rdb$field_name) fldname, rdb$field_position
from rdb$relation_fields
where rdb$system_flag = 0 and trim(rdb$relation_name) = 'SYSTEM'
order by 2
rows 17),
b (declares, flds, wildcards, params) as (
select :crlf || list('declare ' || fldname || ' TYPE OF COLUMN SYSTEM.' || fldname || ';', :crlf) || :crlf,
list(fldname), list('?'), list(':' || fldname)
from a)
select * from b
into :declares, :flds, :wildcards, :params;
-- kurzes statement ohne feldliste?
if (:dstfldcount <= 17) then
insertsql = '''insert into SYSTEM values (' || :wildcards || ')''';
else
insertsql = '''insert into SYSTEM (' || :flds || ') values (' || :wildcards || ')''';
sql = 'execute block returns (result integer) as ' || :declares || 'begin ';
sql = sql || :crlf || ' result = 0;';
sql = sql || :crlf || ' for execute statement ''select * from system'' ';
sql = sql || :crlf || ' on external ''labor'' ';
sql = sql || :crlf || ' into ' || :params || ' ' || :crlf || ' do ' || :crlf || ' begin ';
-- eintragen lokal
sql = sql || :crlf || ' execute statement (' || :insertsql || ') (' || :params || ');';
sql = sql || :crlf || ' result = result + 1; ' || :crlf || ' end ' || :crlf || ' suspend; ' || :crlf || 'end;';
in autonomous transaction
do
execute statement sql
-- anzahl der inserts zurückgeben
into :result;
suspend;
end
Der String, über den er meckert steht in der Spalte ""SCRIPT_USER_NR"
und ist eigentlich viel zu kurz, um einen Overflow zu produzieren.
Auch braucht er eigentlich keine Data-Conversersion, da Source und Ziel-
Tabelle absolut gleich sind.
Vielleicht findest Du ja den Grund in den 3 Bildern.
Die Tabelle hat nur 1 Datensatz.
Danke und Gruss
- Dateianhänge
-
- Labor_Update03.jpg (138.31 KiB) 24099 mal betrachtet
-
- Labor_Update02.jpg (152.87 KiB) 24099 mal betrachtet
-
- Labor_Update01x.jpg (140.97 KiB) 24099 mal betrachtet
Prüfe mal das SQL im Ergebnis ohne die Ausführung.
M.a.W. lass mal den " in autonomous transaction ..." weg.
Es kann durchaus sein, dass ein Syntaxfehler vorliegt und die Meldung ein Folgefehler ist.
M.a.W. lass mal den " in autonomous transaction ..." weg.
Es kann durchaus sein, dass ein Syntaxfehler vorliegt und die Meldung ein Folgefehler ist.
Hallo Hamburgo,
Dein zweiter Screenshot zeigt die Ursache: Du hast unterschiedliche Feldreihenfolgen zwischen Quell- und Zieltabelle. Die SP nimmt sich die Reihenfolge aus der Zieltabelle. Feld SCRIPT_USER_NR wird versucht nach BATCH_DATE zu übertragen, und diese Konvertierung scheitert natürlich.
Du kann ja unterschiedliche Feldreihenfolgen in Quell- und Zieltabelle haben, wenn es dafür einen guten Grund gibt, aber dann musst Du die Quelltabelle so abfragen, dass die Reihenfolge der Felder im Quellselect zu der Reihenfolge der Felder der Zieltabelle passt. Andernfalls mach einfach bei beiden Tabellen die gleiche Feldreihenfolge. Und frag die dann auch so ab
Grüße, Volker
Dein zweiter Screenshot zeigt die Ursache: Du hast unterschiedliche Feldreihenfolgen zwischen Quell- und Zieltabelle. Die SP nimmt sich die Reihenfolge aus der Zieltabelle. Feld SCRIPT_USER_NR wird versucht nach BATCH_DATE zu übertragen, und diese Konvertierung scheitert natürlich.
Du kann ja unterschiedliche Feldreihenfolgen in Quell- und Zieltabelle haben, wenn es dafür einen guten Grund gibt, aber dann musst Du die Quelltabelle so abfragen, dass die Reihenfolge der Felder im Quellselect zu der Reihenfolge der Felder der Zieltabelle passt. Andernfalls mach einfach bei beiden Tabellen die gleiche Feldreihenfolge. Und frag die dann auch so ab

Grüße, Volker
Das ist auch der Grund, warum ich sowas im Programm und nicht in der eingeschränkten SQL-Sprache mache.
Dabei kann man dann auch ebenso erforderliche Konvertierungen (casts) mit unterbringen oder bei fehlenden Mappings Felder auslassen oder Defaultwerte einbringen.
Das Ergebnis dieses Codes lässt sich dann durchaus auch als Execute Block generieren, aber auch hier ist die Ausführung im Client, wenn man auf dem selben Rechner ist, durch Parallelisierung (Reader-Thread, Writer-Thread) durchaus mit ansehnlichem Durchsatz zu leisten (je nach Zeilenlänge mehr als 4000 Inserts/Sekunde).
Dabei kann man dann auch ebenso erforderliche Konvertierungen (casts) mit unterbringen oder bei fehlenden Mappings Felder auslassen oder Defaultwerte einbringen.
Das Ergebnis dieses Codes lässt sich dann durchaus auch als Execute Block generieren, aber auch hier ist die Ausführung im Client, wenn man auf dem selben Rechner ist, durch Parallelisierung (Reader-Thread, Writer-Thread) durchaus mit ansehnlichem Durchsatz zu leisten (je nach Zeilenlänge mehr als 4000 Inserts/Sekunde).
Es hat nichts mit der Sprache zu tun, wenn eine Prozedur nicht richtig benutzt wird, und casts, mapping und defaults sind in SQL auch kein Problem. Die SP erhebt nicht den Anspruch, alle Fehlersituationen abzudecken, sondern erzeugt SQL, um Daten serverseitig von einer DB zu einer anderen zu kopieren, geht dabei von einem einfachen Zusammenhang aus (übereinstimmende Feldreihenfolge zwischen Quelle und Ziel, kompatible Typen), nicht mehr, nicht weniger.
Hamburgo, die Antwort auf Deine Frage steht zwei Postings weiter oben.
Grüße, Volker
Hamburgo, die Antwort auf Deine Frage steht zwei Postings weiter oben.
Grüße, Volker
Hallo Volker,
danke für Deine Erläuterung.
Ich war davon ausgegangen, dass die Feld-Reihenfolge keine Rolle spielt,
sondern das nur gewährleistet sein muss, dass alle Felder in Quell- und
auch der Ziel-DB vorhanden sein müssen.
Aber gut, ist halt so und ja auch keine grosse Hürde das anzupassen.
Bin gespannt, ob es das tatsächlich ist. Wäre cool.
Danke und Gruss
danke für Deine Erläuterung.
Ich war davon ausgegangen, dass die Feld-Reihenfolge keine Rolle spielt,
sondern das nur gewährleistet sein muss, dass alle Felder in Quell- und
auch der Ziel-DB vorhanden sein müssen.
Aber gut, ist halt so und ja auch keine grosse Hürde das anzupassen.
Bin gespannt, ob es das tatsächlich ist. Wäre cool.
Danke und Gruss
Hallo Volker,
vor lauter Ehrgeiz Dein Script/SP zum Laufen zu kriegen und einfach zu liefern, was es dazu
braucht, habe ich den eigentlichen Verwendungszweck der SP völlig aus den Augen verloren.
Sinn und Zweck des Ganzen ist ja im Rahmen eines Software-UPDATEs die Kunden-DB mit
einer neuen Version des DB-Schemas zu versehen.
Das hatte ich auch im Laufe der ersten Posts zu diesem Thread so beschrieben.
Ergo ist das Schema der neuen Update-DB logischerweise immer anders, als das der
aktuellen Kunden-DB.
Wenn die Logik Deiner SP es jedoch zwingend erfordert, dass die Anzahl UND auch die
Reihenfolge der Felder pro Tabelle in beiden DBs gleich sein muss, dann ist sie für diesen
Zweck leider nicht geeignet.
Da liegt wohl leider ein Missverständnis vor.
Ich bräuchte schon eine Logik, die in der Lage ist z.B. in der Tabelle MASCHIENEN die Daten des Feldes SERIEN_NR von der alten DB in die neue DB zu übertragen, auch wenn das Feld im neuen Schema eine neue Position hat, weil davor entweder neue Felder hinzu gekommen sind oder evtl. auch welche gelöscht wurden.
Auch müsste die SP merken, dass ein Feld einer Tabelle im neuen Schema evtl. nicht mehr da ist und dann halt einfach Alt-Daten verloren gehen, weil nicht kopiert werden kann.
Ist das ohne größeren Aufwand machbar ?
Danke und viele Grüße
vor lauter Ehrgeiz Dein Script/SP zum Laufen zu kriegen und einfach zu liefern, was es dazu
braucht, habe ich den eigentlichen Verwendungszweck der SP völlig aus den Augen verloren.
Sinn und Zweck des Ganzen ist ja im Rahmen eines Software-UPDATEs die Kunden-DB mit
einer neuen Version des DB-Schemas zu versehen.
Das hatte ich auch im Laufe der ersten Posts zu diesem Thread so beschrieben.
Ergo ist das Schema der neuen Update-DB logischerweise immer anders, als das der
aktuellen Kunden-DB.
Wenn die Logik Deiner SP es jedoch zwingend erfordert, dass die Anzahl UND auch die
Reihenfolge der Felder pro Tabelle in beiden DBs gleich sein muss, dann ist sie für diesen
Zweck leider nicht geeignet.
Da liegt wohl leider ein Missverständnis vor.
Ich bräuchte schon eine Logik, die in der Lage ist z.B. in der Tabelle MASCHIENEN die Daten des Feldes SERIEN_NR von der alten DB in die neue DB zu übertragen, auch wenn das Feld im neuen Schema eine neue Position hat, weil davor entweder neue Felder hinzu gekommen sind oder evtl. auch welche gelöscht wurden.
Auch müsste die SP merken, dass ein Feld einer Tabelle im neuen Schema evtl. nicht mehr da ist und dann halt einfach Alt-Daten verloren gehen, weil nicht kopiert werden kann.
Ist das ohne größeren Aufwand machbar ?
Danke und viele Grüße