Seite 1 von 1

Feldinhalte aus DBF übernehmen

Verfasst: Di, 05. Okt 2010 15:44
von Koverhage
Hallo,

habe 2 DBF Dateien, Kunde.dbf und kdtemp.dbf.
Die Daten aus kdtemp sollen in kunde übernommen werden.
Bisher habe ich das immer pro Feld codiert, wenn das Feld in kdtemp
nicht vorhanden ist, wird es mit einem vordefinierten Wert belegt,
wie hier:
Local M_lename1 := iif( type( '("kdin")->lename1' ) = "U",space(30),("kdin")->lename1)
Das ist relativ aufwendig, zumal wenn Felder hinzugekommen sind und ich vergessen
habe diese dann in die entsprechende Importroutine aufzunehmen.

Wollte daher eine Routine schreiben, die alle Felder aus der Importdatei
übernimmt, sofern es ein Feld mit gleichem Namen in der Datenbank gibt.

Stehe aber irgendwie auf dem Schlauch mit Fieldget, Fieldput und fieldname
denn die Reihenfolge der Felder muss ja nicht gleich sein.

Kann mich mal jemand schubsen ?

Re: Feldinhalte aus DBF übernehmen

Verfasst: Di, 05. Okt 2010 15:50
von Jan
Hallo Klaus,

kannst Du nicht die Struktur der alten Datenbank mit DbStruct() einlesen, und dieses Array dann Satz für Satz durchgehen? Dann hast Du jedes Feld drin, egal, was mal zwischendurch irgendwann geändert wurde.

Jan

Re: Feldinhalte aus DBF übernehmen

Verfasst: Di, 05. Okt 2010 15:54
von Manfred
Hi Klaus,

wenn Du die Reihenfolge nicht weißt, dann wirst Du wohl um ein Fieldpos nicht herumkommen. Du kennst ja den Namen des Sourcefeldes und damit kannst Du dann in der Zieldatei nach der Platzierung suchen.

Re: Feldinhalte aus DBF übernehmen

Verfasst: Di, 05. Okt 2010 15:57
von Tom
IsFieldVar(<cName>) ermittelt, ob in der selektierten Workarea ein Feld mit dem Namen in "cName" existiert.
FieldPos(<cName>) ermittelt die Position des Feldes.
FieldGet(FieldPos(<cName>)) würde dann den Inhalt des Feldes ermitteln.
FieltPut(FieldPos(<cName>),<xInhalt>) würde den Inhalt von "xInhalt" in dieses Feld schreiben.

Damit hast Du alles nötige zur Verfügung. :wink:

Re: Feldinhalte aus DBF übernehmen

Verfasst: Di, 05. Okt 2010 15:57
von Martin Altmann
Moins,
es werden mit dem normalen APPEND FROM-Kommando eh' nur die Felder importiert, die in der Zieldatenbank vorhanden sind (mit gleichen Namen).

Viele Grüße,
Martin

Re: Feldinhalte aus DBF übernehmen

Verfasst: Di, 05. Okt 2010 18:18
von Koverhage
Martin,

so habe ich es früher gemacht, hatte aber diverse Probleme damit.

Hab mir das in etwa so vorgestellt:

use kunde alias out
use kdtemp alias in

Zunächst alle Sätze in out löschen die dem eingegebenen Kriterium entsprechen.

dann
("out")->(dbappend())

for i:=1 to ("in")->(fcount())
cfeldname := ("in")->(fieldname(i)
("out")->(cfeldname) := ("in")->(cfeldname)
next

unlock

so könnte ich kein Feld vergessen.
Leider funktioniert das Ganze nicht wie ich möchte.
Ich bekomme zwar den Feldnamen, aber die Werte werden nicht nach out übertragen.

Re: Feldinhalte aus DBF übernehmen

Verfasst: Di, 05. Okt 2010 18:49
von Rolf Ramacher
Hi Klaus,

also du wirst mit diesem Verfahren über ein FieldGet und Fieldput() nicht hinwegkommen.

Re: Feldinhalte aus DBF übernehmen

Verfasst: Di, 05. Okt 2010 23:01
von Günter Beyes
Hallo Klaus,

am einfachsten geht's mit dem Makro-Operator.

Code: Alles auswählen

out->&cFeldname := in->&cFeldname
Gruß,
Günter

Re: Feldinhalte aus DBF übernehmen

Verfasst: Mi, 06. Okt 2010 8:09
von brandelh
Hallo Klaus,

sowas habe ich vor einigen Tagen auch gemacht ;-) du must wissen, welche der DBFs bei den Felder führt.
Ich verstehe dich so, dass das IN ist, also die Datei mit den Inputwerten.
Meine Funktion arbeitet bestehende Datensätze ein, ich habe diese nun so umgewandelt, dass nur angehängt wird.
Du musst aber gut testen, ob sich kein Fehler eingeschliechen hat ;-)

Code: Alles auswählen

...
nFeldAnz := IN->(fcount())
aFieldPos := array(nFeldAnz)
for x := 1 to nFeldAnz
     aFieldPos[x] := OUT->(fieldPos( IN->(fieldName(x)) )) // wo steht das Feld
next
IN->(dbGoTop())
do while ! IN->(eof())
    OUT->(dbAppend())
    if neterr()
       Fehlermeldung ...
    endif
    for x := 1 to nFeldAnz // REPLACE
        if aFieldPos[x]>0 // was tun wenn es ein Feld nicht gibt ?
          OUT->(fieldPut(aFieldPos[x], IN->(fieldGet(x))))
        endif
    next
    IN->(dbSkip())
enddo
Falls die OUT Datei mehr Felder hat, werden diese automatisch auf einen BLANK Wert je nach Datentyp gesetzt,
das muss man nicht selbst machen, aber wenn andere Basiswerte gesetzt werden sollen, muss man das natürlich
noch einbauen.

Re: Feldinhalte aus DBF übernehmen

Verfasst: Mi, 06. Okt 2010 9:37
von brandelh
Hi,

wenn du eine Meldung willst, welche Felder NICHT übernommen werden, da in OUT kein Feld existiert ...

Code: Alles auswählen

...
cFehlFeld := ""
nFeldAnz := IN->(fcount())
aFieldPos := array(nFeldAnz)
for x := 1 to nFeldAnz
   aFieldPos[x] := OUT->(fieldPos( IN->(fieldName(x)) )) // wo steht das Feld
   if aFieldPos[x]=0
     // Fehlermeldung je Feld ? oder wie hier einmalig danach
     cFehlFeld += ", "+IN->(fieldName(x))
   endif
next
if ! empty(cFehlFeld)
   msgbox("Folgende Felder werden nicht übernommen:"+chr(13)+substr(cFehlFeld,3),"Mehr Felder in Quelle")
endif

Re: Feldinhalte aus DBF übernehmen

Verfasst: Mi, 06. Okt 2010 15:04
von Koverhage
Hi,

habe mich für diesen Weg entschieden (Günters Methode).
Das ist sogar für mich fast verständlich ;-)

Was mir nicht so ganz klar ist:
Ich war bisher immer der Meinung man könnte den Macrooperator & nicht
mit lokalen Variablen verwenden. Abr in diesem Fall funktioniert das Ganze.
Warum?

Code: Alles auswählen

* --
STATIC PROCEDURE IMP_dbf(nFelder)
* --
Local cFeldname, i:=0
("out")->(DbAppend(1))    // bestehende Satzsperre bleibt erhalten
for i:=1 to nFelder
   cFeldname := ("in")->(fieldname(i))
   ("out")->&cFeldname := ("in")->&cFeldname
next
("out")->(DbrUnlock(recno()))
("out")->(dbskip(0))
RETURN

Re: Feldinhalte aus DBF übernehmen

Verfasst: Mi, 06. Okt 2010 15:24
von brandelh
Hallo,

dein Code hat aber 2 eventuelle Probleme !

1. Wenn in IN ein Feld vorkommt, das in OUT fehlt, dann krachts.
2. Durch die Macrozeile dürfte der Code langsamer sein, als meiner, was aber erst bei großen Dateien eine Rolle spielt (probiert habe ich es nicht ;-) )

wie immer muss ich die Schreibweise ("IN")-> kritisieren (ich kann nicht anders), das ist unnötig !
Wenn du wie hier einen fixen Alias verwendest, dann schreib sollte man den auch direkt
verwenden IN-> der Compiler muss genau dies sonst jede Zeile tun.
->&cFeldname kann je nach Inhalt zu Problemen führen, daher ist es hier besser ->&(cFeldname) zu verwenden.

Und genau aus dem letzten Grund funktioniert das auch, zur Laufzeit wird die Variable
cFeldname nicht mehr angesprochen sondern nur die Speicherstelle wo der Inhalt liegt.
Solange du nur den Inhalt einer Variablen willst, funktioniert & mit local und private.
Nur wenn du die Variable selbst im String angibst, so z.B.:
&("field->Name == alltrim(cSuchName)")
dann geht das nur wenn cSuchName eine Private ist, wobei natürlich das besser ist:
&("field->Name == "+alltrim(cSuchName)+")"

Re: Feldinhalte aus DBF übernehmen

Verfasst: Mi, 06. Okt 2010 16:06
von Tom
Innerhalb von Variablen, die mit dem Makrooperator untersucht werden, dürfen keine LOCALs enthalten sein. Die Variablen selbst können LOCAL sein.

Code: Alles auswählen

LOCAL cTest := "Date()", cTest2 := "cTest"

? &cTest -> Datum
? &cTest2 -> kracht, weil "cTest" LOCAL ist. Wäre es PRIVATE, würde diese Zeile mit "Date()" antworten

Re: Feldinhalte aus DBF übernehmen

Verfasst: Mi, 06. Okt 2010 18:43
von Koverhage
Hallo Hubert,

in out kann das Feld nur theoretisch fehlen. Warum ich das so machen möchte, ist ja der Grund das ich kein Feld
aus in vergessen kann.

Das ("in") kommt daher weil ich mal das C/S System von Phil Ide einsetzen wollte.

Die Geschwindigkeit ist für mich subjektiv betrachtet ausreichend.