@Marin:
ja, die Source- und Ziel-DB liegen auf ja in dem Moment auf demselben Server-PC,
nur halt in unterschiedlichen Laufwerks-Pfaden.
Das findet nur auf dem Server-PC selbst statt und tangiert/braucht das Netzwerk
in keiner Weise.
Folglich kann auch von sehr stabilen DB-Verbindungen ausgegangen werden.
Viele Grüße
Kopieren von Daten von einer DB in eine andere DB
Moderator: thorben.braun
@Martin:
"Das heißt, du musst zwei Schritte berücksichtigen
1. Struktur in Ziel-DB anpassen
2. Neue und modifizierte Daten einspielen"
Nein, genau anders herum:
Alte, vorhandene, Daten in eine "modifizierte" Struktur der Ziel-DB einspielen.
Wobei die Modifizierungen von der "alten" gegenüber der "neuen" Struktur bekannt sind bzw. per Script automatisch ermittelt werden. Das Ermitteln, also Abgleichen zweier DB-Strukturen per Script kann ich inzwischen ziemlich perfekt.
"Das heißt, du musst zwei Schritte berücksichtigen
1. Struktur in Ziel-DB anpassen
2. Neue und modifizierte Daten einspielen"
Nein, genau anders herum:
Alte, vorhandene, Daten in eine "modifizierte" Struktur der Ziel-DB einspielen.
Wobei die Modifizierungen von der "alten" gegenüber der "neuen" Struktur bekannt sind bzw. per Script automatisch ermittelt werden. Das Ermitteln, also Abgleichen zweier DB-Strukturen per Script kann ich inzwischen ziemlich perfekt.
Ich habe da ganz gute Erfahrungen mit DevExpress und deren XAF-Framework gemacht.
Dies entspricht i.W. einem Entity-Framework. Man definiert seine Anwendung, Tabellen und Zugriffe.
Die DB wird automatisch generiert und Änderungen am Modell werden beim nächsten Zugriff automatisch aktualisiert.
Ein Versionswechsel der DB war da dann kein Problem
.
Dies entspricht i.W. einem Entity-Framework. Man definiert seine Anwendung, Tabellen und Zugriffe.
Die DB wird automatisch generiert und Änderungen am Modell werden beim nächsten Zugriff automatisch aktualisiert.
Ein Versionswechsel der DB war da dann kein Problem

Hallo Hamburgo,
Dabei ist quelldb ein Alias für die QuellDB, kann auch ein Connect-String sein,
dann kommt das Quellselect,
20 ist eine fürs Beispiel angenommene Zahl der Felder der Quelldaten, das steuert nur, ob in der SP das insert mit oder ohne Feldliste umgesetzt wird,
und schließlich der Name der Zieltabelle in der ZielDB (lokal). Die Zieltabelle muss existieren und eine passende Struktur haben.
Aufruf für den 2. Fall:
Die SP ist nur ein Codegenerator, sie erzeugt einen execute block, den Du dann ausführen kannst, und der transferiert die Daten.
Die SP:
Grüße, Volker
Unten der Code der CrossDB-SP. Aufruf in der ZielDB, die SP zieht die Daten aus der entfernten QuellDB zu sich lokal, bspw so:Hamburgo hat geschrieben: Fr 8. Apr 2022, 11:49 @Volker:
Mir wäre sehr geholfen, wenn Du mir Muster-Codes für zwei Szenarien geben könntest.
1. Kopiere alle Daten-Sätze "aller" Spalten z.B. der Tabelle "Kunden" von Source-DB.
2. Kopiere aus allen Daten-Sätzen z.B. die Spalten Anrede, Vorname und Nachname aus Tabelle "Kunden"
von Source-DB in Tabelle "Alt_Kunden".
p.s.: Der Vollständigkeit halber die Info, ich nutze unter PHP die FireBird- und die PDO-Extension,
was aber, so glaube ich, hier keine Rolle spielt oder ?
Code: Alles auswählen
select * from get_xdb_insertsql('quelldb', 'select * from kunden', 20, 'kunden')
dann kommt das Quellselect,
20 ist eine fürs Beispiel angenommene Zahl der Felder der Quelldaten, das steuert nur, ob in der SP das insert mit oder ohne Feldliste umgesetzt wird,
und schließlich der Name der Zieltabelle in der ZielDB (lokal). Die Zieltabelle muss existieren und eine passende Struktur haben.
Aufruf für den 2. Fall:
Code: Alles auswählen
select * from get_xdb_insertsql('quelldb', 'select anrede, vorname, nachname from kunden', 3, 'alt_kunden')
Die SP:
Code: Alles auswählen
CREATE PROCEDURE GET_XDB_INSERTSQL (
SRCDBC VARCHAR(100),
SRCSQL VARCHAR(10000),
SRCFLDCOUNT INTEGER,
DSTTBL VARCHAR(30)
)
RETURNS (
"SQL" VARCHAR(20000)
)
AS
begin
-- erzeugt crossdb-SQL für insert in die Zieltabelle und benutzt dazu das "insert" statement
-- input Connect String zur Quell-DB, (SrcDBC), ein Quell-Select (SrcSQL),
-- Anzahl seiner Spalten (SrcFldCount) und der Name der Zieltabelle (DstTbl)
-- Die Feldliste der Zieltabelle werden ermittelt, das SrcSQL muss dieser Feldliste entsprechen
-- Feldtypen der Zieltabelle werden ausgeliehen
-- das SrcSQL muss bis zu SrcFldCount der Struktur der Zieltabelle entsprechen
dsttbl = upper(:dsttbl);
srcsql = replace(:srcsql, '''', '''''''''');
-- SRCDBC auf DB-Alias reduzieren, damit user/pw der aktuellen connection benutzt werden können
srcdbc = substring(:srcdbc from position(':', :srcdbc) + 1);
sql =
'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) = ''' || :dsttbl || ''');
-- 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) = ''' || :dsttbl || '''
order by 2
rows ' || :srcfldcount || '),
b (declares, flds, wildcards, params) as (
select :crlf || list(''declare '' || fldname || '' TYPE OF COLUMN ' || :dsttbl || '.'' || fldname || '';'', :crlf) || :crlf,
list(fldname), list(''?''), list('':'' || fldname)
from a)
select * from b
into :declares, :flds, :wildcards, :params;
-- kurzes statement ohne feldliste?
if (:dstfldcount <= ' || :srcfldcount || ') then
insertsql = ''''''insert into ' || :dsttbl || ' values ('' || :wildcards || '')'''''';
else
insertsql = ''''''insert into ' || :dsttbl || ' ('' || :flds || '') values ('' || :wildcards || '')'''''';
sql = ''execute block returns (result integer) as '' || :declares || ''begin '';
sql = sql || :crlf || '' result = 0;'';
sql = sql || :crlf || '' for execute statement ''''' || :srcsql || ''''' '';
sql = sql || :crlf || '' on external ''''' || :srcdbc || ''''' '';
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';
suspend;
end
;
Hallo Volker,
ich bin schwer beeindruckt was Du mir da alles reingestellt hast !!!
Das ist ja Wahnsinn. Herzlichen Dank für Deine Mühe und den Aufwand.
Hätte ich geahnt, wieviel Zeugs das ist, dann hätte ich mich kaum getraut
danach zu fragen.
Auf den ersten Blick verstehe ich zwar nur "Bahnhof", gehe aber davon aus,
nach ein paar Stunden Hirn-Jogging und üben wird schon Licht ins Dunkle
kommen.
Danke und viele Grüße
Hamburgo
ich bin schwer beeindruckt was Du mir da alles reingestellt hast !!!
Das ist ja Wahnsinn. Herzlichen Dank für Deine Mühe und den Aufwand.
Hätte ich geahnt, wieviel Zeugs das ist, dann hätte ich mich kaum getraut
danach zu fragen.
Auf den ersten Blick verstehe ich zwar nur "Bahnhof", gehe aber davon aus,
nach ein paar Stunden Hirn-Jogging und üben wird schon Licht ins Dunkle
kommen.
Danke und viele Grüße
Hamburgo
Hallo Volker,
nachdem ich nun endlich alle Probleme in Sachen CharSet's aus dem
Weg geräumt habe, geht es nun an den 2. Versuch Deine SP zum Laufen
zu bringen.
Der 1. Versuch war eben genau an diesen falschen CharSet's in meinen DB's gescheitert,
was auch gut so war, da erst dieser die Schwere des Problems mir deutlich gemacht hat.
Ich hatte es mir anders erhoft, aber nicht wirklich erwartet, dass dieser gleich klappt.
Leider fliegt dieser der mir wenig sagenden Meldung um die Ohren:
1. Dieser Teil zeigt, dass Deine SP in der DB vorhanden ist:
2. Die Tabelle, die ich für diesem Versuch genommen habe, hat in Quell- und Ziel-DB folgende Struktur:
3. Dieser Teil zeigt, mit welcher Systax ich die SP angesprochen habe und die Meldung:
Habe ich evtl. irgendwelche Hochkommas oder Vergleichbares vergessen ?
Danke und viele Grüße
nachdem ich nun endlich alle Probleme in Sachen CharSet's aus dem
Weg geräumt habe, geht es nun an den 2. Versuch Deine SP zum Laufen
zu bringen.
Der 1. Versuch war eben genau an diesen falschen CharSet's in meinen DB's gescheitert,
was auch gut so war, da erst dieser die Schwere des Problems mir deutlich gemacht hat.
Ich hatte es mir anders erhoft, aber nicht wirklich erwartet, dass dieser gleich klappt.
Leider fliegt dieser der mir wenig sagenden Meldung um die Ohren:
Folgendes kann ich an Info's liefern:SQLSTATE[HY000]: General error: -804 Dynamic SQL Error SQL error code = -804 Incorrect values within SQLDA structure
1. Dieser Teil zeigt, dass Deine SP in der DB vorhanden ist:
Code: Alles auswählen
$Select = SELECT * FROM RDB$PROCEDURES WHERE RDB$PROCEDURE_NAME='GET_XDB_INSERTSQL';
Connect-String: >//localhost/E:/DataBase/Labor_Update.FDB, SYSDBA, HomePassword<
$Record:
Array
(
[RDB$PROCEDURE_NAME] => GET_XDB_INSERTSQL
[RDB$PROCEDURE_ID] => 1
[RDB$PROCEDURE_INPUTS] => 4
[RDB$PROCEDURE_OUTPUTS] => 1
[RDB$DESCRIPTION] =>
[RDB$PROCEDURE_SOURCE] => begin
-- erzeugt crossdb-SQL für insert in die Zieltabelle und benutzt dazu das "insert" statement
-- input Connect String zur Quell-DB, (SrcDBC), ein Quell-Select (SrcSQL),
-- Anzahl seiner Spalten (SrcFldCount) und der Name der Zieltabelle (DstTbl)
-- Die Feldliste der Zieltabelle werden ermittelt, das SrcSQL muss dieser Feldliste entsprechen
-- Feldtypen der Zieltabelle werden ausgeliehen
-- das SrcSQL muss bis zu SrcFldCount der Struktur der Zieltabelle entsprechen
dsttbl = upper(:dsttbl);
srcsql = replace(:srcsql, '''', '''''''''');
-- SRCDBC auf DB-Alias reduzieren, damit user/pw der aktuellen connection benutzt werden können
srcdbc = substring(:srcdbc from position(':', :srcdbc) + 1);
sql =
'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) = ''' || :dsttbl || ''');
-- 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) = ''' || :dsttbl || '''
order by 2
rows ' || :srcfldcount || '),
b (declares, flds, wildcards, params) as (
select :crlf || list(''declare '' || fldname || '' TYPE OF COLUMN ' || :dsttbl || '.'' || fldname || '';'', :crlf) || :crlf,
list(fldname), list(''?''), list('':'' || fldname)
from a)
select * from b
into :declares, :flds, :wildcards, :params;
-- kurzes statement ohne feldliste?
if (:dstfldcount <= ' || :srcfldcount || ') then
insertsql = ''''''insert into ' || :dsttbl || ' values ('' || :wildcards || '')'''''';
else
insertsql = ''''''insert into ' || :dsttbl || ' ('' || :flds || '') values ('' || :wildcards || '')'''''';
sql = ''execute block returns (result integer) as '' || :declares || ''begin '';
sql = sql || :crlf || '' result = 0;'';
sql = sql || :crlf || '' for execute statement ''''' || :srcsql || ''''' '';
sql = sql || :crlf || '' on external ''''' || :srcdbc || ''''' '';
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';
suspend;
end
;
[RDB$PROCEDURE_BLR] => &5d&5'&5&5 N&5 N-›g))ºREPLACE)''''')()#"ºPOSITION:)ÿÿÿ)'''''''''''''''''';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) = ')ì');
-- 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) = ')'
order by 2
rows )w),
b (declares, flds, wildcards, params) as (
select :crlf || list('declare ' || fldname || ' TYPE OF COLUMN )ó.' || fldname || ';', :crlf) || :crlf,
list(fldname), list('?'), list(':' || fldname)
from a)
select * from b
into :declares, :flds, :wildcards, :params;
-- kurzes statement ohne feldliste?
if (:dstfldcount <= )') then
insertsql = '''insert into )K values (' || :wildcards || ')''';
else
insertsql = '''insert into )æ (' || :flds || ') values (' || :wildcards || ')''';
sql = 'execute block returns (result integer) as ' || :declares || 'begin ';
sql = sql || :crlf || ' result = 0;';
sql = sql || :crlf || ' for execute statement '')0'' ';
sql = sql || :crlf || ' on external '')à'' ';
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)ÿ›ÿÿÿÿ)ÿÿL
[RDB$SECURITY_CLASS] => SQL$9
[RDB$OWNER_NAME] => SYSDBA
[RDB$RUNTIME] =>
[RDB$SYSTEM_FLAG] => 0
[RDB$PROCEDURE_TYPE] => 1
[RDB$VALID_BLR] => 1
[RDB$DEBUG_INFO] => SRCDBCSRCSQLSRCFLDCOUNTDSTTBLSQLSQL?AOwT´TQ ÿ
)
GET_XDB_INSERTSQL-Check_Procedur: $numRowS = 1
Code: Alles auswählen
CREATE TABLE SYSTEM (
RID_SYSTEM RID NOT NULL,
SYSTEM_NR STXT,
LIZENZ_NR STXT,
AKTIV SI DEFAULT 0,
DATEN TS DEFAULT '11.11.1111 00:00',
DATENBANK TS DEFAULT '11.11.1111 00:00',
EDITDATE TS DEFAULT '11.11.1111 00:00',
INDATE TS DEFAULT 'NOW',
STATUS SI DEFAULT 0,
SCRIPT MTXT,
SCRIPT_USER_NR STXT,
SCRIPT_USER STXT,
BATCH_SCRIPT MTXT,
BATCH_DATE TS DEFAULT '11.11.1111 00:00',
ANDROID TS DEFAULT '11.11.1111 00:00',
DISTANCEMATRIX BI DEFAULT 0,
GEOCODING BI DEFAULT 0
);
Code: Alles auswählen
$SQL: >select * from get_xdb_insertsql('//localhost/E:/DataBase/Labor.FDB, SYSDBA, HomePassword', 'select * from system', 17, 'system')<
Connect-String: >//localhost/E:/DataBase/Labor_Update.FDB, SYSDBA, HomePassword<
$Message: >SQLSTATE[HY000]: General error: -804 Dynamic SQL Error SQL error code = -804 Incorrect values within SQLDA structure <
Danke und viele Grüße
Hallo Volker,
heute Morgen habe ich Deine von mir gestern eingetragene SP gelöscht und nochmals
Dein Original von oben sorgfälltig eingestellt, um sicher zu stellen, dass mir gestern kein Copy&Paste-Fehler unterlaufen ist.
Leider hat das nichts gebracht.
heute Morgen habe ich Deine von mir gestern eingetragene SP gelöscht und nochmals
Dein Original von oben sorgfälltig eingestellt, um sicher zu stellen, dass mir gestern kein Copy&Paste-Fehler unterlaufen ist.
Leider hat das nichts gebracht.
Hallo Hamburgo,
Missverständnis, der Connectstring ist nicht richtig, es muss ohne username/password sein. Connectstring im Sinne von Firebird, nicht aus Anwendungssicht wie etwa php, wo eine ganze Funktion mit Connectstring und Logindaten kommagetrennt aufgerufen wird.
Allerdings geht die SP von DB-Aliasen aus und nicht von kompletten Pfadangaben zu einer DB. Das hab ich vergessen zu erwähnen, sorry. Wenn Du Dir in databases.conf (oder aliases.conf, falls FB25) einen Alias labor so definierst:
wird der Aufruf zu
localhost kannst Du weglassen, denn Du bist ja bereits auf dem Zielserver, connectest dort nur aus der ZielDB zur DB labor, und der Server lauscht auf dem Standardport, dh
reicht, wenn Du den DB-Alias definiert hast.
Zur der Sache, dass die SP in der DB vorhanden ist: Verwendest Du kein DB-Admintool wie Flamerobin o.ä.? Denn da sieht man gleich in der Liste der Prozeduren, welche da sind. Du musst nicht die Systemtabellen dafür abfragen.
Grüße, Volker
Missverständnis, der Connectstring ist nicht richtig, es muss ohne username/password sein. Connectstring im Sinne von Firebird, nicht aus Anwendungssicht wie etwa php, wo eine ganze Funktion mit Connectstring und Logindaten kommagetrennt aufgerufen wird.
Code: Alles auswählen
select * from get_xdb_insertsql('//localhost/E:/DataBase/Labor.FDB', 'select * from system', 17, 'system')
Code: Alles auswählen
labor = E:\DataBase\Labor.FDB
Code: Alles auswählen
select * from get_xdb_insertsql('//localhost/labor', 'select * from system', 17, 'system')
Code: Alles auswählen
select * from get_xdb_insertsql('labor', 'select * from system', 17, 'system')
Zur der Sache, dass die SP in der DB vorhanden ist: Verwendest Du kein DB-Admintool wie Flamerobin o.ä.? Denn da sieht man gleich in der Liste der Prozeduren, welche da sind. Du musst nicht die Systemtabellen dafür abfragen.
Grüße, Volker
Hallo Volker,
vielen Dank für die aufklärende Antwort.
Ob ich das hinbekomme, wie von Dir beschrieben, weiss ich noch nicht,
weil ich mich noch nie mit DB-Aliasen beschäftigt habe.
Das ist Neu-Land für mich. Ich werde Dir berichten.
Danke und viele Grüße
vielen Dank für die aufklärende Antwort.
Ob ich das hinbekomme, wie von Dir beschrieben, weiss ich noch nicht,
weil ich mich noch nie mit DB-Aliasen beschäftigt habe.
Das ist Neu-Land für mich. Ich werde Dir berichten.

Danke und viele Grüße
Hallo Volker,
zu Deinem letzten Absatz:
Doch, ich verwende u.a. IB-Expert. Damit habe ich auch Deine SP in die DB gebracht
und konnte das dort natürlich auch sofort sehen, dass die SP drin ist.
Die Abfrage in meinem Script auf die System-Tabelle habe ich nur deshalb eingebaut,
um über diese Kontroll-Abfrage sicherzustellen, dass ich nicht versehentlich die falsche
DB anspreche oder sonstige Syntax-Fehler begehe.
Da wusste ich ja noch nichts von dem Erfordernis eines DB-Aliases für Deine SP.
Jetzt erklärt sich natürlich das Scheitern meines Versuches. Vorher war ich echt
der Verzweiflung nahe.
zu Deinem letzten Absatz:
Doch, ich verwende u.a. IB-Expert. Damit habe ich auch Deine SP in die DB gebracht
und konnte das dort natürlich auch sofort sehen, dass die SP drin ist.
Die Abfrage in meinem Script auf die System-Tabelle habe ich nur deshalb eingebaut,
um über diese Kontroll-Abfrage sicherzustellen, dass ich nicht versehentlich die falsche
DB anspreche oder sonstige Syntax-Fehler begehe.
Da wusste ich ja noch nichts von dem Erfordernis eines DB-Aliases für Deine SP.
Jetzt erklärt sich natürlich das Scheitern meines Versuches. Vorher war ich echt
der Verzweiflung nahe.