Seite 1 von 2

[gelöst]Daten von einer Datenbank in eine andere kopieren

Verfasst: Sa 3. Okt 2015, 19:24
von malt14
Guten Tag,

ausgehend vom Makro im Gesamtband V50 (S. 447f) versuchte ich, dies in einer Datenbank anzuwenden. Ich erhalte diese Fehlermeldung:
basic.PNG
basic.PNG (54.57 KiB) 4418 mal betrachtet
Liegt das an meiner Version: 4.4.5.2?

Sowohl die benutzte Datenbank als auch die Zieldatenbank sind angemeldet. Die Zieldatenbank befindet sich auf einer anderen Festplatte (D:\).

Wie könnte man ein Update der Tabelle in der Zieldatenbank erreichen, also auch geänderte und nicht nur neue Datensätze entsprechen der Ausgangsdatenbank oder alle bestehenden Datensätze der Tabelle in der Zieldatenbank werden gelöscht und alle Datensätze der Ausgangsdatenbank einfügt?


Falls man die Datensätze mehrerer Tabellen anfügen oder updaten will, geht dies, indem man in das Makro Kopien des ursprünglichen Makros mit den entsprechend geänderten Tabellen und Feldnamen einfügt?

Code: Alles auswählen

REM  *****  BASIC  *****

SUB Datenkopie
DIM oDatabaseContext AS OBJECT
DIM oDatenquelle AS OBJECT
DIM oDatenquelleZiel AS OBJECT
DIM oVerbindung AS OBJECT
DIM oVerbindungZiel AS OBJECT
DIM oDB AS OBJECT
DIM oSQL_Anweisung AS OBJECT
DIM oSQL_AnweisungZiel AS OBJECT
DIM oAbfrageergebnis AS OBJECT
DIM oAbfrageergebnisZiel AS OBJECT
DIM stSql AS String
DIM stSqlZiel AS String
DIM inID AS INTEGER
DIM inIDZiel AS INTEGER
DIM stName AS STRING
DIM stOrt AS STRING
oDB = ThisComponent.Parent
stDir = Left(oDB.Location,Len(oDB.Location)-Len(oDB.Title))
stDir = ConvertToUrl(stDir & "test.odb")
oDatenquelle = ThisComponent.Parent.CurrentController
If NOT (oDatenquelle.isConnected()) THEN
oDatenquelle.connect()
END IF
oVerbindung = oDatenquelle.ActiveConnection()
oDatabaseContext = createUnoService("com.sun.star.sdb.DatabaseContext")
oDatenquelleZiel = oDatabaseContext.getByName(stDir)
oVerbindungZiel = oDatenquelleZiel.GetConnection("","")
oSQL_Anweisung = oVerbindung.createStatement()
stSql = "SELECT * FROM ""Tabelle1"""
oAbfrageergebnis = oSQL_Anweisung.executeQuery(stSql)
WHILE oAbfrageergebnis.next
inID = oAbfrageergebnis.getInt(1)
stName = oAbfrageergebnis.getString(2)
stOrt = oAbfrageergebnis.getString(3)
oSQL_AnweisungZiel = oVerbindungZiel.createStatement()
stSqlZiel = "SELECT ""ID"" FROM ""Tabelle1"" WHERE ""ID"" = '"+inID+"'"
oAbfrageergebnisZiel = oSQL_AnweisungZiel.executeQuery(stSqlZiel)
inIDZiel = - 1
WHILE oAbfrageergebnisZiel.next
inIDZiel = oAbfrageergebnisZiel.getInt(1)
WEND
IF inIDZiel = - 1 THEN
stSqlZiel = "INSERT INTO ""Tabelle1"" (""ID"",""name"") VALUES 
('"+inID+"','"+stname+"')"
oSQL_AnweisungZiel.executeUpdate(stSqlZiel)
END IF
WEND

DIM oDatabaseContext AS OBJECT
DIM oDatenquelle AS OBJECT
DIM oDatenquelleZiel AS OBJECT
DIM oVerbindung AS OBJECT
DIM oVerbindungZiel AS OBJECT
DIM oDB AS OBJECT
DIM oSQL_Anweisung AS OBJECT
DIM oSQL_AnweisungZiel AS OBJECT
DIM oAbfrageergebnis AS OBJECT
DIM oAbfrageergebnisZiel AS OBJECT
DIM stSql AS String
DIM stSqlZiel AS String
DIM inID AS INTEGER
DIM inIDZiel AS INTEGER
DIM stName AS STRING
DIM stOrt AS STRING
oDB = ThisComponent.Parent
stDir = Left(oDB.Location,Len(oDB.Location)-Len(oDB.Title))
stDir = ConvertToUrl(stDir & "test.odb")
oDatenquelle = ThisComponent.Parent.CurrentController
If NOT (oDatenquelle.isConnected()) THEN
oDatenquelle.connect()
END IF
oVerbindung = oDatenquelle.ActiveConnection()
oDatabaseContext = createUnoService("com.sun.star.sdb.DatabaseContext")
oDatenquelleZiel = oDatabaseContext.getByName(stDir)
oVerbindungZiel = oDatenquelleZiel.GetConnection("","")
oSQL_Anweisung = oVerbindung.createStatement()
stSql = "SELECT * FROM ""Tabelle2"""
oAbfrageergebnis = oSQL_Anweisung.executeQuery(stSql)
WHILE oAbfrageergebnis.next
inID = oAbfrageergebnis.getInt(1)
stName = oAbfrageergebnis.getString(2)
stOrt = oAbfrageergebnis.getString(3)
oSQL_AnweisungZiel = oVerbindungZiel.createStatement()
stSqlZiel = "SELECT ""ID"" FROM ""Tabelle2"" WHERE ""ID"" = '"+inID+"'"
oAbfrageergebnisZiel = oSQL_AnweisungZiel.executeQuery(stSqlZiel)
inIDZiel = - 1
WHILE oAbfrageergebnisZiel.next
inIDZiel = oAbfrageergebnisZiel.getInt(1)
WEND
IF inIDZiel = - 1 THEN
stSqlZiel = "INSERT INTO ""Tabelle2"" (""ID"",""name2"") VALUES 
('"+inID+"','"+stname2+"')"
oSQL_AnweisungZiel.executeUpdate(stSqlZiel)
END IF
WEND

END SUB

Grüße
Malt

LibreOffice
Version: 4.4.5.2
Gebietsschema: de_DE
Microsoft Windows 8.1 Home 6.03.9600 x64

Re: Daten von einer Datenbank in eine andere kopieren

Verfasst: Sa 3. Okt 2015, 19:42
von RobertG
Hallo Malt,

schon der Screenshot macht mich stutzig. In der Folgezeile der angemerkten Codezeile steht Code in grauer Farbe. Das deutet darauf hin, dass der Editor von einem Kommentar ausgeht. Das erste Zeichen, die offne Klammer, ist dunkelblau - Code wie z.B. eine Zuweisung "=".

Hinter dem Begriff "VALUES" scheint ein Zeilenumbruch eingebaut zu sein. Dadurch wird der String unterbrochen. Nimm den Zeilenumbruch raus, dann hast Du damit mehr Erfolg.

------------------------------
Willst Du nicht nur neue Daten in die Zieltabelle übertragen, sondern auch gegebenenfalls Updates, so ist dies problemlos am Schluss der Makros möglich:

Code: Alles auswählen

WEND
IF inIDZiel = - 1 THEN
stSqlZiel = "INSERT INTO ""Tabelle"" (""ID"",""Name"") VALUES ('"+inID+"','"+stName+"')"
ELSE
stSqlZiel = "UPDATE ""Tabelle"" SET ""Name"" = '"+stName+"' WHERE ""ID"" = '"+inID+"'"
END IF
oSQL_AnweisungZiel.executeUpdate(stSqlZiel)
inIDZiel klärt ja vorher ab, ob der Datensatz schon existiert. Bei '-1' existiert der Datensatz noch nicht - ein neuer Datensatz wird geschrieben. Sonst wird ein alter Datensatz überschrieben.
--------------------------------

Gruß

Robert

Re: Daten von einer Datenbank in eine andere kopieren

Verfasst: Sa 3. Okt 2015, 22:44
von malt14
Hallo Robert,

vielen Dank für Deine Hilfe! Entsprechend Deinem Hinweis entfernte ich den Zeilenumbruch.
Ich kopierte das Makro aus dem Handbuch und bearbeitete es in Writer. Beim Einfügen entsteht der Zeilenumbruch, der mir nicht auffiel.

Eine neue Fehlermeldung:
basic2.PNG
basic2.PNG (57.86 KiB) 4408 mal betrachtet
Makro:

Code: Alles auswählen

REM  *****  BASIC  *****

SUB Datenkopie
DIM oDatabaseContext AS OBJECT
DIM oDatenquelle AS OBJECT
DIM oDatenquelleZiel AS OBJECT
DIM oVerbindung AS OBJECT
DIM oVerbindungZiel AS OBJECT
DIM oDB AS OBJECT
DIM oSQL_Anweisung AS OBJECT
DIM oSQL_AnweisungZiel AS OBJECT
DIM oAbfrageergebnis AS OBJECT
DIM oAbfrageergebnisZiel AS OBJECT
DIM stSql AS String
DIM stSqlZiel AS String
DIM inID AS INTEGER
DIM inIDZiel AS INTEGER
DIM stName AS STRING
DIM stOrt AS STRING
oDB = ThisComponent.Parent
stDir = Left(oDB.Location,Len(oDB.Location)-Len(oDB.Title))
stDir = ConvertToUrl(stDir & "test.odb")
oDatenquelle = ThisComponent.Parent.CurrentController
If NOT (oDatenquelle.isConnected()) THEN
oDatenquelle.connect()
END IF
oVerbindung = oDatenquelle.ActiveConnection()
oDatabaseContext = createUnoService("com.sun.star.sdb.DatabaseContext")
oDatenquelleZiel = oDatabaseContext.getByName(stDir)
oVerbindungZiel = oDatenquelleZiel.GetConnection("","")
oSQL_Anweisung = oVerbindung.createStatement()
stSql = "SELECT * FROM ""Tabelle1"""
oAbfrageergebnis = oSQL_Anweisung.executeQuery(stSql)
WHILE oAbfrageergebnis.next
inID = oAbfrageergebnis.getInt(1)
stName = oAbfrageergebnis.getString(2)
stOrt = oAbfrageergebnis.getString(3)
oSQL_AnweisungZiel = oVerbindungZiel.createStatement()
stSqlZiel = "SELECT ""ID"" FROM ""Tabelle1"" WHERE ""ID"" = '"+inID+"'"
oAbfrageergebnisZiel = oSQL_AnweisungZiel.executeQuery(stSqlZiel)
inIDZiel = - 1
WHILE oAbfrageergebnisZiel.next
inIDZiel = oAbfrageergebnisZiel.getInt(1)
WEND
IF inIDZiel = - 1 THEN
stSqlZiel = "INSERT INTO ""Tabelle1"" (""ID"",""name"") VALUES ('"+inID+"','"+stname+"')"
oSQL_AnweisungZiel.executeUpdate(stSqlZiel)
END IF
WEND
END SUB
LibreOffice Version: 4.4.5.2


Grüße
Malt

Re: Daten von einer Datenbank in eine andere kopieren

Verfasst: So 4. Okt 2015, 08:38
von RobertG
Hallo Malt,

aus dem Handbuch, direkt über dem Code:
Der Kontakt zur Ausgangsdatenbank wird im Verhältnis zum Formular ermittelt, in dem der Button liegt: ThisComponent.Parent.CurrentController. Der Kontakt zur externen Datenbank wird über den DatabaseContext und den Pfad zur Datenbank erstellt.
Ich vermute, dass Du das Makro nicht aus einem Formular heraus mit einem Button starten willst, sondern z.B. direkt von der Base-Oberfläche. Da gibt es dann keinen 'Parent'. Weder bei oDB (wäre dann einfach oDB = ThisComponent) noch bei oDatenquelle (wäre dann oDatenquelle = ThisComponent.CurrentController).

Gruß

Robert

Re: Daten von einer Datenbank in eine andere kopieren

Verfasst: So 4. Okt 2015, 16:00
von malt14
Hallo Robert,

den Grund für mein "Parent" Problem erkanntest Du richtig. Funktioniert jetzt mit Verweis in der Symbolleiste.
Herzlichen Dank!

Meine Zieldatenbank liegt in einem anderen Verzeichnis auf einer anderen Festplatte (D:\xx\xx\zdb), Quelldatenbank (C:\xx\xx\qdb). Beide sind bei LO angemeldet. Dann funktioniert das Makro nicht. Kann man in das Makro den jeweiligen Dateipfad der Datenbanken eintragen?

Einige Datensätze (Namen) enthalten das Zeichen ', dann stoppt das Makro.

Grüße
Malt

Re: Daten von einer Datenbank in eine andere kopieren

Verfasst: So 4. Okt 2015, 17:23
von RobertG
Hallo Malt,
malt14 hat geschrieben: Meine Zieldatenbank liegt in einem anderen Verzeichnis auf einer anderen Festplatte (D:\xx\xx\zdb), Quelldatenbank (C:\xx\xx\qdb). Beide sind bei LO angemeldet. Dann funktioniert das Makro nicht. Kann man in das Makro den jeweiligen Dateipfad der Datenbanken eintragen?
Die Datenbank, von der aus Du das Ganze aufrufst, ist die Quelldatenbank. Da kann vom Pfad her nichts schief gehen.
Der Pfad zur Zieldatenbank wird hier definiert:

Code: Alles auswählen

stDir = ConvertToUrl(stDir & "ZielDB.odb")
Es wird also der Pfad zur Quelldatenbank ausgelesen und statt der Quelldatenbank die Zieldatenbank eingefügt.
Du kannst jetzt folgendermaßen vorgehen:

Code: Alles auswählen

stDir = ConvertToUrl("D:\xx\xx\zdb")
Dann kannst Du Dir diese Zeilen sparen:

Code: Alles auswählen

oDB = ThisComponent.Parent
stDir = Left(oDB.Location,Len(oDB.Location)-Len(oDB.Title))
stDir = ConvertToUrl(stDir & "ZielDB.odb")
Ob die Datenbanken angemeldet sind oder nicht spielt hierbei keine Rolle. Bei den vielen Testdatenbanken habe ich auf Anmeldungen der Datenbanken verzichtet und nutze stattdessen immer den Pfad.
malt14 hat geschrieben: Einige Datensätze (Namen) enthalten das Zeichen ', dann stoppt das Makro.
Nutze diese Funktion:

Code: Alles auswählen

FUNCTION String_to_SQL(st AS STRING)
IF InStr(st,"'") THEN
st = Join(Split(st,"'"),"''")
END IF
String_to_SQL = st
END FUNCTION
Steht im Handbuch unter
Daten aus Textfeldern auf SQL-Tauglichkeit vorbereiten
Gruß

Robert

Re: Daten von einer Datenbank in eine andere kopieren

Verfasst: So 4. Okt 2015, 23:01
von malt14
Hallo Robert,

vielen Dank für die Hilfe zur Zieldatenbank und den Hinweis zur Hochkomma Funktion.
Ich las den Abschnitt darüber im Handbuch. Wie man eine Funktion in ein Makro einbaut und diese dann z.B. für stname ("Datenkopie") aufruft, weiß ich nicht. Dazu fand ich im Internet und Handbüchern nichts; ich kenne zu wenig von Makros, um erfolgreich zu suchen.

In meinen Tabellen benutze ich Feldnamen mit Leerzeichen. Das Makro funktioniert damit nicht. Setze ich den Feldnamen mit Leerzeichen in eckige Klammern "DIM [stname ID] AS STRING", funktioniert das Makro bis oSQL_AnweisungZiel.executeUpdate(stSqlZiel). Dann folgt die Fehlermeldung: Column not found: [stname ID].
Gibt es eine Möglichkeit Feldnamen mit Leerzeichen in Makros zu benutzen?


Grüße

Malt

Re: Daten von einer Datenbank in eine andere kopieren

Verfasst: Mo 5. Okt 2015, 09:08
von RobertG
Hallo Malt,

die Feldnamen in Tabellen haben nichts mit Namensbezeichnungen innerhalb von Makros zu tun. In Makros solltest Du tunlichst Variablen ohne irgendwelche Sonderzeichen erstellen. Ich nutze als Trennung hier gegebenenfalls den Unterschied zwischen Klein- und Großschreibung (der keine weitere Auswirkungen hat) oder den Unterstrich.

Code: Alles auswählen

stSqlZiel = "INSERT INTO ""Tabelle1"" (""ID"",""name"") VALUES ('"+inID+"','"+stname+"')"
Die Bezeichner für das Tabellenfeld sind in der ersten Klammer enthalten. Hier kannst Du zwischen die doppelten Anführungszeichen genau Deine Feldnamen eintragen:

Code: Alles auswählen

stSqlZiel = "INSERT INTO ""Tabelle1"" (""stname ID"",""name"") VALUES ('"+inID+"','"+stname+"')"
Die Meldung
Column not found: [stname ID]
deutet darauf hin, dass Du dort jetzt eben

Code: Alles auswählen

stSqlZiel = "INSERT INTO ""Tabelle1"" (""[stname ID]"",""name"") VALUES ('"+inID+"','"+stname+"')"
stehen hast. Und die Feldbezeichnung hast Du doch wohl nicht gewollt, oder?

Zum Einsatz der Funktion, die Hochkommata richtig maskiert:

Code: Alles auswählen

stTextneu = String_to_SQL(stTextalt)
steht als Aufrufbeispiel im Handbuch.
Dann gibt es in dem Makro, das Du nutzt, diese Zeilen:

Code: Alles auswählen

WHILE oAbfrageergebnis.next
inID = oAbfrageergebnis.getInt(1)
stName = oAbfrageergebnis.getString(2)
stOrt = oAbfrageergebnis.getString(3)
....
Jetzt setzt Du die Funktion ein:

Code: Alles auswählen

WHILE oAbfrageergebnis.next
inID = oAbfrageergebnis.getInt(1)
stName = String_to_SQL(oAbfrageergebnis.getString(2))
stOrt = String_to_SQL(oAbfrageergebnis.getString(3))
....
Damit sind die Variablen entsprechend maskiert. inID brauchst Du nicht zu maskieren, da es sich um eine Integer-Variable handelt.

Gruß

Robert

Re: Daten von einer Datenbank in eine andere kopieren

Verfasst: Mo 5. Okt 2015, 18:22
von malt14
Hallo Robert,

vielen Dank für Deine Erklärungen!
Die Feldnamen funktionieren.

Im Handbuch wird der Grund für und die Arbeitsweise der Funktion String_to_SQL gut erklärt.
Ich wusste bisher nicht, dass man eine Funktion am Ende eines Makros unter End Sub einfügt. Mit der Beispielsdatenbank Beispiel_PDFFormular_Import lernte ich das.

Beim Aufruf von Datenkopie erhalte ich die Meldung "Wrong data type":
type.PNG
type.PNG (23.48 KiB) 4345 mal betrachtet
Das geschieht gelegentlich auch, wenn ich Daten manuell in eine Datenbank kopiere, obwohl diese denselben Datentyp wie die Zielspalte besitzen.

Soweit wie ich das bisher feststellen konnte, werden mit dem Makro Datenkopie trotz o.g. Meldung alle Datensätze korrekt in die Tabelle der Zieldatenbank kopiert.

Nochmals herzlichen Dank für Deine Hilfe und Geduld.

Grüße
Malt

Re: [gelöst]Daten von einer Datenbank in eine andere kopieren

Verfasst: Mo 5. Okt 2015, 21:20
von RobertG
Hallo Malt,

anscheinend versuchst Du in ein Zahlenfeld ein leeren String zu kopieren. Das Makro selbst ist erst einmal auf ein einfaches Beispiel gestrickt: Lediglich das Feld "ID" besteht aus Zahlen. Die Zahlen müssen immer gefüllt sein, da es der Primärschlüssel ist. Alle anderen Felder sind Textfelder. Leere Textfelder werden als leerer String übergeben.

Das geht für Textfelder, aber eben nicht für Zahlenfelder. Hier müsste an dem Makro noch nachgebessert werden. Leere Felder sollten grundsätzlich als NULL weitergegeben werden. Da steht schließlich nichts drin.

Ich nehme mir in den nächsten Tage das Makro noch einmal vor.

Gruß

Robert