Seite 1 von 1
Spaltenköpfe einer Datenbank ändern, zufügen und löschen
Verfasst: Fr, 25. Nov 2016 11:07
von JosuaWilhelm
Hallo zusammen
Habe leider keinen Beitrag zu dem Thema Spaltenköpfe von Datenbanken gefunden.
Wie kann ich vorhandene Spaltenköpfe einer Datenbank ändern oder löschen und neue hinzufügen?
Vielen Dank!
Gruß,
Josua Wilhelm
Re: Spaltenköpfe einer Datenbank ändern, zufügen und löschen
Verfasst: Fr, 25. Nov 2016 12:36
von Manfred
Hi,
meinst Du damit das Ändern der DBF-Struktur?
Re: Spaltenköpfe einer Datenbank ändern, zufügen und löschen
Verfasst: Fr, 25. Nov 2016 12:45
von JosuaWilhelm
Ja, genau.
Re: Spaltenköpfe einer Datenbank ändern, zufügen und löschen
Verfasst: Fr, 25. Nov 2016 12:53
von Manfred
es kommt darauf an, was Du möchtest.
Ich habe mir eine Routine geschrieben, die eine neue DBF mit der neuen gewünschten Struktur erstellt und dann die Daten aus der alten dbf übernimmt. Das geht allerdings nicht mal eben so. Man muß/ sollte wissen, wie man sich verhält, wenn sich Felderbreiten, Feldtypen usw. ändern. Die Frage stellt sich hier, ob Du etwas pauschales machen möchtest, oder bis ins kleinste Detail geplante?
Wie gesagt, sobald sich z.B. feldbreiten, oder Feldtypen ändern, muß aufgepasst und evtl. angepasst werden beim Import. Wenn nur neue Spalten hinzugefügt oder entfernt werden, dann kann einfach importiert werden.
Re: Spaltenköpfe einer Datenbank ändern, zufügen und löschen
Verfasst: Mo, 28. Nov 2016 9:50
von Armin
Hallo Josua Wilhelm,
z.B. per eigenem Programm:
Code: Alles auswählen
AAdd( aStructure, {"FREI_TERMS","D",8,0} )
AAdd( aStructure, {"FREI_TERMI","D",8,0} )
ADDFIELDS(cPath, cAlias, aStructure)
FUNCTION ADDFIELDS(cPfad, cAlias, aNeu)
// Datei um Felder erweitern oder falls bereits vorhanden, in der Größe ändern
// Vorsicht, wenn Felder kleiner gemacht werden, kann Inhalt verloren gehen
LOCAL aStructure
LOCAL I := 0
LOCAL nPos := 0
LOCAL cDat := ""
LOCAL cTemp:= ""
local cFullPath := cPfad+cAlias
dbUseArea( .t. ,,cFullPath, cAlias,.t.,.f.) // shared
aStructure := DbStruct() // Datei-Struktur einlesen
(cAlias)->DbCloseArea()
FOR I:= 1 TO len(aNeu)
nPos := ascan(aStructure, {|a| a[1] == aNeu[I,1]})
if nPos > 0
// Feld bereits vorhanden, Grösse ändern
aStructure[nPos,3] := aNeu[I,3]
aStructure[nPos,4] := aNeu[I,4]
else
AAdd( aStructure, aNeu[I] ) // neu
endif
NEXT
DbCreate(cPfad+"TEMP", aStructure ) // Temporaere Datei mit neuer Struktur erzeugen
dbUseArea( .t. ,,cPfad+"TEMP", "TEMP",.t.,.f.) // exclusive
APPEND FROM &cFullPath // Datensaetze laden aus Quelldatei
CLOSE TEMP
COPY FILE (cFullPath+".dbf") TO (cFullPath+"_si.dbf") // Quelldatei sichern
FERASE(cFullPath+".dbf") // Quelldatei löschen
cTemp:= cPfad+"TEMP.DBF"
cDat := cFullPath+".dbf"
RENAME (cTemp) TO (cDat) // Temporäre Datei umbenennen
IF File( cPfad+"TEMP.DBT" ) // Wenn Memo-Datei existiert
COPY FILE (cFullPath+".dbt") TO (cFullPath+"_si.dbt")
FERASE(cFullPath+".dbt") // Alte Datei l”schen
cTemp:= cPfad+"TEMP.DBT"
cDat := cFullPath+".dbt"
RENAME (cTemp) TO (cDat) // Temporäre Datei umbenennen
ENDIF
RETURN .T.
Re: Spaltenköpfe einer Datenbank ändern, zufügen und löschen
Verfasst: Mo, 28. Nov 2016 23:54
von azzo
Hallo,
könnte man, wenn es zB nur um das Ändern der Spaltenköpfe einer Datenbank geht das einfach mit Überschreiben im Spaltenkopf lösen.
lg
Otto
Re: Spaltenköpfe einer Datenbank ändern, zufügen und löschen
Verfasst: Di, 29. Nov 2016 20:27
von brandelh
war das nun eine Frage ?
Da die DBF ja vom Aufbau her bekannt ist, könnte man tatsächlich mit fopen() etc. die passende Stelle (feldname) überschreiben.
Gemacht habe ich das aber noch nicht.
Ich nutze eine Funktion, die ein Array oder 2 dbf miteinander vergleicht und neue Felder aufnimmt.
Felder löschen geht nicht damit und bei Typänderungen bin ich mir jetzt nicht sicher, ich bin ja im Urlaub ... auf Fuerteventura.
Die Tage schaue ich mal nach, wobei es einige Beispiele bei copy structure gibt (aus dem Gedächtnis).
Re: Spaltenköpfe einer Datenbank ändern, zufügen und löschen
Verfasst: Di, 29. Nov 2016 21:09
von AUGE_OHR
brandelh hat geschrieben:Da die DBF ja vom Aufbau her bekannt ist, könnte man tatsächlich mit fopen() etc. die passende Stelle (feldname) überschreiben.
Gemacht habe ich das aber noch nicht.
interessante Idee ... aber der Name muss dann "genau so lang" (?) sein wie der alter sonst stimmt die Grösse ( Header ) nicht mehr
unter dBase III+ war es der Befehl "MODI STRU" was unter Cl*pper dann DbStruct() -> Array ergab.
wenn man nun einen "bestehenden" Feldnamen ändert wird beim anschliessenden APPEND FROM das Feld nicht gefüllt !
Re: Spaltenköpfe einer Datenbank ändern, zufügen und löschen
Verfasst: Mi, 30. Nov 2016 8:06
von Tom
Ja, das kann man so machen. Die Header sind simpel. Einfach mal z.B. mit einem Hex-Editor ausprobieren! Das geht sogar bei Memos.
Re: Spaltenköpfe einer Datenbank ändern, zufügen und löschen
Verfasst: Do, 01. Dez 2016 1:13
von brandelh
AUGE_OHR hat geschrieben: ... aber der Name muss dann "genau so lang" (?) sein wie der alter sonst stimmt die Grösse ( Header ) nicht mehr
soweit ich mich erinnere sind da genau 10 Zeichen vorgesehen, nicht mehr aber auch nicht weniger.
Re: Spaltenköpfe einer Datenbank ändern, zufügen und löschen
Verfasst: Do, 01. Dez 2016 9:32
von Tom
Genau: Maximal 10 Großbuchstaben (!), fehlende Zeichen aufgefüllt durch 0-Strings (Chr(0)). Danach folgen Typ, Länge usw. Es gibt keine Prüfsummen oder ähnliches. Trotzdem würde ich viel mehr als den Feldnamen auf diese Weise nicht ändern. Das geht auch eleganter mit DbStruct()/DbImport()/DbExport usw.
Re: Spaltenköpfe einer Datenbank ändern, zufügen und löschen
Verfasst: Do, 01. Dez 2016 13:50
von Sören
Hallo Josua,
zu dem, was Tom oben beschrieben hat, hier eine Funktion zur Änderung des Feldnamens einer DBF-Tabelle:
Code: Alles auswählen
// - Feldnamen einer DBF (mittels Low-Level-Dateifunktionen) aendern
// - die DBF darf nicht in Benutzung sein, da die Funktion sie exklusiv oeffnen muss
// - bei erfolgreicher Aenderung des Feldnamens wird .T. zurueckgegeben, andernfalls .F.
// - Bsp.: RenameField( "d:\temp\artikel.dbf", "artnr", "artikelnr" )
FUNCTION RenameField( cFileName, cOldFieldName, cNewFieldName )
LOCAL lSuccess := .F.
LOCAL nHandle
LOCAL nHeaderLength
LOCAL nPointer := 32, nPos
LOCAL cFieldName, aFieldNames := {}
LOCAL cBytes
cFileName := AllTrim( cFileName )
cOldFieldName := Upper( AllTrim( cOldFieldName ) )
cNewFieldName := Upper( AllTrim( cNewFieldName ) )
// Feldname darf nicht laenger als 10 Zeichen sein
if Len( cNewFieldName ) > 10
RETURN .F.
endif
// File konnte geoeffnet werden
if ( nHandle := FOpen( cFileName, FO_READWRITE ) ) != -1
cBytes := Space( 2 )
FSeek( nHandle, 8, FS_SET ) // beim 8ten Byte steht die Groesse des Dateiheaders
FRead( nHandle, @cBytes, 2 ) // die 2 Bytes, die die Laenge des Dateiheaders enthalten, auslesen
nHeaderLength := Bin2I( cBytes ) // in numerischen Wert umwandeln
// - die Feldbeschreibung beginnt bei Byte 32
// - die Angaben fuer ein Feld sind 32 Bytes lang
// - im Folgenden werden alle Feldnamen mit Pointer in das Array aFieldNames eingelesen
cBytes := Space( 10 )
while ( nPointer + 32 ) < nHeaderLength // in 32er Schritten, so lange bis nHeaderLength ueberschritten
FSeek( nHandle, nPointer, FS_SET ) // auf Feldbeschreibung f. Feld n positionieren
// - Feldnamen lesen (10 Zeichen)
// - Chr(0) durch Nullstring "" ersetzen
FRead( nHandle, @cBytes, 10 ) // Feldnamen einlesen
cFieldName := StrTran( cBytes, Chr(0), "" )
cFieldName := Upper( AllTrim( cFieldName ) )
AAdd( aFieldNames, { cFieldName, nPointer } )
nPointer += 32
enddo
// neuer Feldname existiert noch nicht
if AScan( aFieldNames, { |a| a[1] == cNewFieldName } ) == 0
// alter Feldname wurde gefunden
if ( nPos := AScan( aFieldNames, { |a| a[1] == cOldFieldName } ) ) > 0
// ggf. auf 11 Zeichen mit Chr(0) auffuellen
cNewFieldName := PadR( cNewFieldName, 11, Chr(0) )
nPointer := aFieldNames[nPos][2]
FSeek( nHandle, nPointer, FS_SET ) // auf zu aendernden Feldnamen positionieren
if ( FWrite( nHandle, cNewFieldName ) > 0 ) // neuen Feldnamen in Datei schreiben
lSuccess := .T.
endif
endif
endif
FClose( nHandle )
endif
RETURN lSuccess
Re: Spaltenköpfe einer Datenbank ändern, zufügen und löschen
Verfasst: Do, 01. Dez 2016 19:02
von brandelh
Tom hat geschrieben:Genau: Maximal 10 Großbuchstaben (!), fehlende Zeichen aufgefüllt durch 0-Strings (Chr(0)). ... Trotzdem würde ich viel mehr als den Feldnamen auf diese Weise nicht ändern.
genau meine Meinung, beim reinen Namen geht es grad so aber ansonsten ... umkopieren.
Re: Spaltenköpfe einer Datenbank ändern, zufügen und löschen
Verfasst: Fr, 02. Dez 2016 18:03
von Schorsch
Hallo Josua,
der Kollege Hubert Brandel
hat mir mal mit dem Programm DBU.EXE geholfen und das verwende ich heute noch zur Administration von DBF Dateien und damit sind Umbenennungen und Typ-Änderungen etc alles möglich.
Gruß
Georg
Re: Spaltenköpfe einer Datenbank ändern, zufügen und löschen
Verfasst: Sa, 03. Dez 2016 23:19
von brandelh
wobei DBU standardmäßig Probleme damit hat wenn die Datentypen sich ändern.
Re: Spaltenköpfe einer Datenbank ändern, zufügen und löschen
Verfasst: Mi, 07. Dez 2016 13:38
von JosuaWilhelm
Hallo zusammen,
vielen Dank Euch für Eure Antworten und Programm-Beispiele!
Probiere diese gerade aus und melde mich wieder ...
Danke und liebe Grüße,
Josua Wilhelm
Re: Spaltenköpfe einer Datenbank ändern, zufügen und löschen
Verfasst: Mi, 07. Dez 2016 16:43
von JosuaWilhelm
Armin hat geschrieben:Hallo Josua Wilhelm,
z.B. per eigenem Programm:
Code: Alles auswählen
AAdd( aStructure, {"FREI_TERMS","D",8,0} )
AAdd( aStructure, {"FREI_TERMI","D",8,0} )
ADDFIELDS(cPath, cAlias, aStructure)
FUNCTION ADDFIELDS(cPfad, cAlias, aNeu)
// Datei um Felder erweitern oder falls bereits vorhanden, in der Größe ändern
// Vorsicht, wenn Felder kleiner gemacht werden, kann Inhalt verloren gehen
LOCAL aStructure
LOCAL I := 0
LOCAL nPos := 0
LOCAL cDat := ""
LOCAL cTemp:= ""
local cFullPath := cPfad+cAlias
dbUseArea( .t. ,,cFullPath, cAlias,.t.,.f.) // shared
aStructure := DbStruct() // Datei-Struktur einlesen
(cAlias)->DbCloseArea()
FOR I:= 1 TO len(aNeu)
nPos := ascan(aStructure, {|a| a[1] == aNeu[I,1]})
if nPos > 0
// Feld bereits vorhanden, Grösse ändern
aStructure[nPos,3] := aNeu[I,3]
aStructure[nPos,4] := aNeu[I,4]
else
AAdd( aStructure, aNeu[I] ) // neu
endif
NEXT
DbCreate(cPfad+"TEMP", aStructure ) // Temporaere Datei mit neuer Struktur erzeugen
dbUseArea( .t. ,,cPfad+"TEMP", "TEMP",.t.,.f.) // exclusive
APPEND FROM &cFullPath // Datensaetze laden aus Quelldatei
CLOSE TEMP
COPY FILE (cFullPath+".dbf") TO (cFullPath+"_si.dbf") // Quelldatei sichern
FERASE(cFullPath+".dbf") // Quelldatei löschen
cTemp:= cPfad+"TEMP.DBF"
cDat := cFullPath+".dbf"
RENAME (cTemp) TO (cDat) // Temporäre Datei umbenennen
IF File( cPfad+"TEMP.DBT" ) // Wenn Memo-Datei existiert
COPY FILE (cFullPath+".dbt") TO (cFullPath+"_si.dbt")
FERASE(cFullPath+".dbt") // Alte Datei l”schen
cTemp:= cPfad+"TEMP.DBT"
cDat := cFullPath+".dbt"
RENAME (cTemp) TO (cDat) // Temporäre Datei umbenennen
ENDIF
RETURN .T.
Ich habe es mit diesem Programm versucht, aber irgendwie funktioniert das Löschen mit FErase() jeweils nicht.
Wenn ich andere Dateinamen inklusiv Pfad an dieser Stelle eintrage, werden sie gelöscht.
Kann es sein, dass Xbase die dbfs noch irgendwo geöffnet hält und sie deshalb nicht gelöscht werden können?
Der Rückgabewert von FErase() beträgt "-1".
Re: Spaltenköpfe einer Datenbank ändern, zufügen und löschen
Verfasst: Do, 08. Dez 2016 8:22
von brandelh
es könnte sein, dass append from eine Datei noch offen hält, oder ein Virenscanner ...
Diese Funktion wird von mir benutzt:
Code: Alles auswählen
*--------------------------------------------------------------------------
function DBMixStru(cZielDBF,acHinzu, nZielDBF) // cZielDBF = Pfad+Dateiname der alten DBF.
// acHinzu = Array mit neuen Feldern nach dbstru()
// oder = Pfad+Dateiname der hinzuzufügenden DBF.
// nZielDBF = wenn cZielDBF schon exclusiv offen ist, hier den Selectbereich oder Alias angeben.
// DATEN werden nicht hinzugefügt !
// nur neue Felder / Feldlängen als Vorbereitung
// Wenn beide gleich sind, wird nichts geändert.
// .t. -> keine Fehler
// .f. -> Fehler sind aufgetreten.
local lFehler := .f.
local aQuellStru, aHinzuStru, cTempDat
local lStruNeu := .f.
local x, nQI
/*
die DBF etc. Endungen müssen entfernt werden, da
1. temporäre Dateinamen gebildet werden müssen
2. eventuelle DBT oder FPT Dateien vorhanden sein könnten.
*/
if ! empty(nZielDBF)
if ! (nZielDBF)->(used())
nZielDBF := NIL
endif
endif
if right(cZielDBF,4) = ".DBF" // Endung abtrennen
cZielDBF := left(cZielDBF,len(cZielDBF)-4)
endif
cTempDat := cZielDBF+"_TMP_"+strTran(time(),":","")
if empty(nZielDBF) // nil oder leer => cZielDBF ist nicht offen.
USE (cZielDBF) NEW exclusive alias MixStruQuelle // diese Datei muß exclusiv öffenbar sein.
if neterr()
lFehler := .t.
else
nZielDBF := select()
endif
endif
if ! lFehler
// die Quelldatei bleibt offen, bis geklärt ist ob eine Anpassung nötig ist.
// sonst könnte ein anderes Programm die Datei öffnen.
aQuellStru := (nZielDBF)->(dbstruct())
endif
// Strukturarrays erzeugen
do case
case lFehler
// ohne Quelldatei geht nichts mehr.
case ValType(acHinzu) = "A"
aHinzuStru := acHinzu
case ValType(acHinzu) = "C"
if right(acHinzu,4) = ".DBF" // Endung abtrennen
acHinzu := left(acHinzu,len(acHinzu)-4)
endif
USE (acHinzu) NEW readonly alias MixStruHinzu
if neterr()
lFehler := .t.
else
aHinzuStru := MixStruHinzu->(dbstruct())
endif
otherwise
lFehler := .t.
endcase
// Neue Struktur ermitteln
do case
case lFehler
// ohne Quelldatei geht nichts mehr.
case empty(aQuellStru) .or. empty(aHinzuStru)
lFehler := .t.
otherwise
for x := 1 to len(aHinzuStru) // alle neuen Felder prüfen !
nQI := aScan(aQuellStru,{|aF| aF[DBS_NAME] == upper(aHinzuStru[x,DBS_NAME])})
if nQI > 0 // Feld ist vorhanden, TYP und Längen prüfen
if aQuellStru[nQI,DBS_TYPE] == aHinzuStru[x,DBS_TYPE] // TYP ist gleich
if aQuellStru[nQI,DBS_LEN] # aHinzuStru[x,DBS_LEN] .or. ;
aQuellStru[nQI,DBS_DEC] # aHinzuStru[x,DBS_DEC]
lStruNeu := .t. // Länge der Felder wurde geändert.
aQuellStru[nQI,DBS_LEN] := max(aQuellStru[nQI,DBS_LEN],aHinzuStru[x,DBS_LEN])
aQuellStru[nQI,DBS_DEC] := max(aQuellStru[nQI,DBS_DEC],aHinzuStru[x,DBS_DEC])
endif
else // Neuer TYP, neue Werte übernehmen
lStruNeu := .t.
aQuellStru[nQI,DBS_TYPE] := aHinzuStru[x,DBS_TYPE]
aQuellStru[nQI,DBS_LEN] := aHinzuStru[x,DBS_LEN]
aQuellStru[nQI,DBS_DEC] := aHinzuStru[x,DBS_DEC]
endif
else // neues Feld, alles übernehmen
lStruNeu := .t.
aadd(aQuellStru, {aHinzuStru[x,1],aHinzuStru[x,2],aHinzuStru[x,3],aHinzuStru[x,4]})
endif
next
endcase
// nun haben wir die neue Struktur der Datei falls Änderungen vorhanden waren.
if (nZielDBF)->(USED())
(nZielDBF)->(dbCloseArea())
endif
if USED("MixStruHinzu")
close MixStruHinzu
endif
// Änderungen nötig ?
if lStruNeu // Anpassungen nötig
// dürfte nicht vorkommen, aber sicher ist sicher
delete file (cTempDat+".DBF")
delete file (cTempDat+".DBT")
delete file (cTempDat+".FPT")
rename (cZielDBF+".DBF") to (cTempDat+".DBF")
rename (cZielDBF+".DBT") to (cTempDat+".DBT")
rename (cZielDBF+".FPT") to (cTempDat+".FPT")
dbcreate(cZielDBF, aQuellStru)
use (cZielDBF) NEW exclusive ALIAS MixStruZiel
DbImport(cTempDat)
close MixStruZiel
// alte Versionen bis zur nächsten Anpassung stehen lassen
* delete file (cTempDat+".DBF")
* delete file (cTempDat+".DBT")
* delete file (cTempDat+".FPT")
endif
return ! lFehler
Re: Spaltenköpfe einer Datenbank ändern, zufügen und löschen
Verfasst: Do, 08. Dez 2016 9:26
von JosuaWilhelm
Ok, das mit dem FErase() hat jetzt funktioniert nachdem ich davor noch CLOSE DATABASES eingefügt habe.
Aber bei allen aufgeführten Beispielen finde ich die Funktion nicht für das Löschen eines Spaltenkopfes.
Es werden nur die Optionen für das Ändern oder Hinzufügen einer Spalte aufgeführt.
Liege ich da richtig oder habe ich etwas übersehen?
Re: Spaltenköpfe einer Datenbank ändern, zufügen und löschen
Verfasst: Do, 08. Dez 2016 10:30
von brandelh
Das stimmt wohl, denn ich füge nur Felder hinzu, aber wenn du dir AADD() bei der Struktur ansiehst:
Code: Alles auswählen
AAdd( aStructure, {"FREI_TERMS","D",8,0} )
AAdd( aStructure, {"FREI_TERMI","D",8,0} )
das Gegenteil davon ist einfach eine Felddefinition zu löschen, wie gesagt wenn das bei dir vorkommt ...
früher musste man da zwei Befehle ausführen:
beim Append From werden ja alle Felder ignoriert, die in der neuen Datei nicht mehr vorhanden sind.