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 :D 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 ...

Code: Alles auswählen

ARemove( <aArray>    , [<nStartPos>],  [<nCount>]     ) 
früher musste man da zwei Befehle ausführen:

Code: Alles auswählen

ADel()
ASize()
beim Append From werden ja alle Felder ignoriert, die in der neuen Datei nicht mehr vorhanden sind.