German In bestehender SQL-Datei Felder ändern

tudorf

Active Member
Licensed User
Longtime User
Hallo
Ich stehe immer noch mit SQL auf Kriegsfuss. Ich habe eine bestehnde Datei die mit meiner Anwendung unter B4A funktioniert. Nun muss ich die Datei um mehrer Felder erweitern. Ich gehe wie folgt vor:
- Die alte Datei im Verzeichnis Files copieren und einen neuen Namen vergeben.
- Öffnen der neuen Datei mit SQLite
- Erweitern der Dateistruktur z.B. "Infofeld" Char
- Trennen der Datei
- Im B4A unter Files die alte Datei löschen und mit ADD die neue Datei hinzufügen.
- Variable DBFileName im Programm ändern.
- Kompilieren und aufs Handy übertragen.

Leider kennt das Programm die neuen Felder nicht.

Wo liegt mein Fehler ?

Wo finde ich die Datei in der schon Daten sind auf seinem Handy?

In dem Verzeichnis was durch File.DirInternal angegeben wird ist leer. Mit dem Windows-Explorer gibt es auf dem ganzen Handy keine Datei mit dem Namen.

Ist die Datei ein Bestandteil des Apk-Datei ?
Danke Martin
 

klaus

Expert
Licensed User
Longtime User
Ohne Deinen Code zu sehen ist es schwierig konkrete Hilfe zu leisten.

- Erweitern der Dateistruktur z.B. "Infofeld" Char was ist Char, sollte es TEXT sein ?
- Trennen der Datei was verstehst Du hier ?
Kopierst Du die neue Datei zu Files.DirInternal

Mit dem Windows-Explorer kannst Du Files.DirInternal nicht sehen.
Files.DirInternal kann nur von Deinem Programm angesprochen werden.
Um zu testen ob eine bestimmte Datei existiert kannst Du folgendes verwenden.
B4X:
If File.Exits(File.DirInternal, Dateiname)= True Then
Beste Grüsse.
 

Paulsche

Well-Known Member
Licensed User
Longtime User
Wenn ich in meiner Tabelle ein neues Feld hinzufüge,
mache ich das so, dass ich die Anzahl der Felder (Spalten) abfrage,
wenn das Feld noch nicht vorhanden ist, dann neues Feld zufügen und in allen
Datensätzen das neue Feld mit einem Wert belegen.

B4X:
If cr_Tankdaten.ColumnCount =13 Then                                 'Wenn Spalte beleg Tankdaten-DB noch fehlt
      SQLtnk.ExecNonQuery("alter TABLE tankdaten add column beleg TEXT")         'Neue Spalte erstellen
      SQLtnk.ExecNonQuery("UPDATE tankdaten SET beleg=''")                  'Spalte beleg vorbelegen
   End If
 

tudorf

Active Member
Licensed User
Longtime User
Hallo Klaus

> Erweitern der Dateistruktur z.B. "Infofeld" Char was ist Char, sollte es TEXT sein ?
In meinem SQLiteManager gibt es Integer,Bool, Real, Double, Float, Char, Text, VarChar, Blob, Numeric und Datetime. In der alten Datei funktioniert der Typ Char.

> Trennen der Datei was verstehst Du hier ? Das ist ein Menüpunkt im SQLiteManager. Ich verbinde den Manager mit der Datenbank, ändere die Datenstruktur und trenne die Datei wieder.

> Kopierst Du die neue Datei zu Files.DirInternal
Ich denke hier liegt mein Problem. Das Verzeichnis was mir angezeigt wird finde ich nicht. File.dirInternal zeigt mir /data/data/mystery.b4a.files. Ich habe die Datei in alle möglichen Verzeichnisse kopiert.

Ich denke ich versuche es mit der Methode von Paulsche

Ich habe folgende Zeilen erstellt
SQL1.ExecNonQuery("alter TABLE gccode add column test TEXT")
SQL1.ExecNonQuery("UPDATE gccode SET test=''")

Dabei ist gccode meine Tabelle und test ist das neue Feld vom Typ TEXT.
Beim ersten Aufruf sagt mir das Programm dass das feld TEST doppelt definiert ist.

Beim zweiten Aufruf, ohne die beiden ExecNonQuery-Befehle, zeigt mir der Debuger java.lang.NullPointerException. Das Feld ist nicht in der Datenbank.

Martin
 
Last edited:

tudorf

Active Member
Licensed User
Longtime User
Du meinst den Bereich
If File.Exists(DBFileDir, DBFileName) = False Then
IfFirstTime Then
usw.

Der Bereich ist bei mir vorhanden. Die Datenbank mit der alten Dateistruktur (Mystery4.db) ist auf dem Handy vorhanden und funktioniert ohne Probleme. Die neue Datei mit der erweiterten Struktur (Mystery5.db) ist auf dem PC in Verzeichnis Files bei einem B4A-Projekt. Weiterhin in einigen Verzeichnissen auf dem Handy wo ich gehofft hatte, dass das B4A-Programm darauf zugreift.

Die Verzeichnisse, die mit B4A z.B. mit File.Dir.Internal angibt gibt es nicht oder ich kann nicht mit Windows darauf zugreifen.

Ich habe eine Listbox auf der Basis vom Sample: ListviewDircontentImagebox installiert. Es gibt eine Datei im Verzeichnis File.Dir.Internal mit dem Namen Mystery5.db. Da ich meine neuen Dateien mit einer neuen Struktur immer umbenenne kann es keine alte Struktur sein. Aber die neuen Felder sind nicht bekannt.

Die Prüfung mit File.Exists(DBFileDir, DBFileName) gibt true zurück. Auch hier ist die Datenbank vorhanden.

Ich programmiere seit 1987 unsere Firmensoftware. Erst unter DOS dann unter Windows. Ich arbeite zwar nicht mit SQL sondert verwalte meine vielen Datenbanken selber aber so viele Probleme eine Datei zu verändern kenne ich nicht. Es kann doch nicht sein, dass ich nun ein Programm scheiben muss was Datenstrukturen auf dem handy ausliest, die Struktur verändert und wieder abspeichert.

Warum gibt mir B4A bei den folgenden Zeilen eine Fehlermeldung zurück, das das Feld schon vergeben ist?

'SQL1.ExecNonQuery("alter TABLE gccode add column test TEXT")
'SQL1.ExecNonQuery("UPDATE gccode SET test=''")

Martin
 

Paulsche

Well-Known Member
Licensed User
Longtime User
Hallo, deshalb frage ich die Anzahl der Spalten ab,
so dass die neue Spalte nur zugefügt wird wenn die Anzahl ohne
die neue Spalte ist.

Beim erstellen der Tabelle (create) muss die Spalte natürlich auch vorhanden sein,
das hinzufügen ist ja nur für schon bestehende Tabelle.

Hier mein kompletter Code für DB-Initialisierung
B4X:
Sub init_db                                                         ' Datenbanken laden
   If File.IsDirectory(File.DirDefaultExternal, "Tankbelege") = False Then         ' wenn Verzeichnis für Tankbelege nicht vorhanden
      File.MakeDir(File.DirDefaultExternal, "Tankbelege")                     ' Verzeichnis erstellen
   End If
   
   If File.Exists(File.DirDefaultExternal, "Tankdaten.db") = False Then         ' wenn Tankdaten DB nicht vorhanden
      If SQLtnk.IsInitialized = False Then
         SQLtnk.Initialize(File.DirDefaultExternal, "Tankdaten.db", True)      ' Tankdaten DB initialisieren
      End If
      SQLtankdatenCreate                                             ' Tankdaten DB erstellen
   Else                                                         ' Tankdaten DB ist vorhanden
      If SQLtnk.IsInitialized = False Then
         SQLtnk.Initialize(File.DirDefaultExternal, "Tankdaten.db", True)      ' Tankdaten DB initialisieren      
      End If
   End If
   
   If File.Exists(File.DirDefaultExternal, "KFZdaten.db") = False Then            ' wenn KFZ DB nicht vorhanden
      If SQLkfz.IsInitialized = False Then
         SQLkfz.Initialize(File.DirDefaultExternal, "KFZdaten.db", True)         ' KFZ DB initialisieren
      End If
      SQLkfzdatenCreate                                             ' KFZ DB erstellen
   Else
      If SQLkfz.IsInitialized = False Then
         SQLkfz.Initialize(File.DirDefaultExternal, "KFZdaten.db", True)         ' KFZ DB initialisieren
      End If
   End If

   If File.Exists(File.DirDefaultExternal, "Kosten.db") = False Then            ' wenn Kosten DB nicht vorhanden
      If SQLkosten.IsInitialized = False Then
         SQLkosten.Initialize(File.DirDefaultExternal, "Kosten.db", True)      ' Kosten DB initialisieren
      End If
      SQLkostenCreate                                                ' Kosten DB erstellen
   Else
      If SQLkosten.IsInitialized = False Then
         SQLkosten.Initialize(File.DirDefaultExternal, "Kosten.db", True)      ' Kosten DB initialisieren
      End If
   End If

   If File.Exists(File.DirDefaultExternal, "Tankorte.db") = False Then            ' wenn Tankorte DB nicht vorhanden
      If SQLorte.IsInitialized = False Then
         SQLorte.Initialize(File.DirDefaultExternal, "Tankorte.db", True)      ' Tankorte DB initialisieren
      End If
      SQLtankorteCreate                                             ' Tankorte DB erstellen
   Else
      If SQLorte.IsInitialized = False Then
         SQLorte.Initialize(File.DirDefaultExternal, "Tankorte.db", True)      ' Tankorte DB initialisieren
      End If
   End If

   cr_Tankdaten    = SQLtnk.ExecQuery("select * from tankdaten")               'Für Spaltenabfrage notwendig
   cr_kosten       = SQLkosten.ExecQuery("select * from kosten")               'Für Spaltenabfrage notwendig
   If cr_Tankdaten.ColumnCount =11 Then                                 'Wenn Spalten Tickszeit + Zeit in Tankdaten-DB noch fehlt
      Dim zeit_string,zeit_ticks As String
      zeit_string = "12:00"
      zeit_ticks   = DateTime.TimeParse(zeit_string)
      SQLtnk.ExecNonQuery("alter TABLE tankdaten add column tickszeit TEXT")      'Neue Spalte erstellen
      SQLtnk.ExecNonQuery("alter TABLE tankdaten add column zeit TEXT")         'Neue Spalte erstellen
      SQLtnk.ExecNonQuery("UPDATE tankdaten SET tickszeit='"&DateTime.TimeParse(zeit_string)&"', zeit='"&zeit_string&"'")'Spalte objekt mit Wert vorbelegen
   End If
   If cr_Tankdaten.ColumnCount =13 Then                                 'Wenn Spalte beleg Tankdaten-DB noch fehlt
      SQLtnk.ExecNonQuery("alter TABLE tankdaten add column beleg TEXT")         'Neue Spalte erstellen
      SQLtnk.ExecNonQuery("UPDATE tankdaten SET beleg=''")                  'Spalte beleg vorbelegen
   End If
   If cr_kosten.ColumnCount =11 Then                                    'Wenn Spalte "intervall" in Kosten-DB noch fehlt
      SQLkosten.ExecNonQuery("alter TABLE kosten add column intervall TEXT")      'Neue Spalte erstellen
      SQLkosten.ExecNonQuery("UPDATE kosten SET intervall='Einmalig'")         'Spalte intervall mit Wert vorbelegen
   End If
End Sub
 
Last edited:

tudorf

Active Member
Licensed User
Longtime User
Hallo paulsche

Reden wir von den selben Dingen ?

Ich habe eine SQL-Datei mit der Tabelle gccode. Hier habe ich folgende Felder:
ColumnName(0) = "id"
ColumnName(1) = "gccode"
ColumnName(2) = "nord1"
ColumnName(3) = "nord2"
ColumnName(4) = "nord3"
ColumnName(5) = "ost1"
ColumnName(6) = "ost2"
ColumnName(7) = "ost3"
ColumnName(8) = "infofeld"
ColumnName(9) = "hint"
ColumnName(10) = "name"
ColumnName(11) = "gelaende"
ColumnName(12) = "groesse"
Das klappt und funktioniert. Nun möchte ich einmalig folgende Felder hinzufügen:
ColumnName(13) = "art"
ColumnName(14) = "schwierig"
ColumnName(15) = "ort"
ColumnName(16) = "update"
ColumnName(17) = "gefunden"
ColumnName(18) = "info1"
ColumnName(19) = "info2"
Nur einmal und nicht immer wieder.
Martin
 

tudorf

Active Member
Licensed User
Longtime User
Kein Problem

Sub Activity_Create(FirstTime As Boolean)

Dim i As Int

Activity.LoadLayout("Anzeige")

'File.Delete(DBFileDir, DBFileName) ' bloss zum Testen, löscht die Datenbank und lädt die Originaldatenbank
If FirstTime Then
If File.Exists(DBFileDir, DBFileName) = False Then
Msgbox("Datei wird kopiert","")
File.Copy(File.DirAssets, DBFileName, DBFileDir, DBFileName)
End If
RowIDs.Initialize
SQL1.Initialize(DBFileDir, DBFileName, True)
End If

SQL1.ExecNonQuery("alter TABLE gccode add column test TEXT")
SQL1.ExecNonQuery("UPDATE gccode SET test=''")

' initialisiert die internen Spaltenbreiten und Links (Left)
TotalColumnWidth(0) = ColLineWidth
For i = 0 To NumberOfColumns - 1
ColumnWidth_1(i) = ColumnWidth(i) - ColLineWidth
TotalColumnWidth(i + 1) = TotalColumnWidth(i) + ColumnWidth(i)
Next

End Sub

Sub Activity_Resume
fill_view
End Sub

Sub fill_view

ClearAll

SetHeader(ColumnName)
NumberOfRows = 0

RowIDs.Clear

Dim Cursor1 As Cursor
Cursor1 = SQL1.ExecQuery("SELECT * FROM " & DBTableName)

For i = 0 To Cursor1.RowCount - 1
Dim Col(NumberOfColumns) As String

Cursor1.Position = i
For j = 0 To NumberOfColumns - 1
Col(j) = Cursor1.GetString(ColumnName(j))
Next
RowIDs.Add(Col(0))
AddRow(Col)
Next

Cursor1.Close
Activity.Title = DBFileName

End Sub
 

klaus

Expert
Licensed User
Longtime User
Welchen Wert hat DBFileName, Mystery5.db oder Mystery4.db ?

Hast Du auch den Wert von NumberOfColumns geändert ?
Hast du die Arrays ColumnWidth(i), ColumnWidth_1(i) usw. mit dem neuen NumberOfColumns Wert deklariert ?

Wenn Deine neue Datenbank die neuen Spalten schon beinhaltet brauchst Du die beiden Zeilen von Paulsche nicht.

Beste Grüsse.
 

tudorf

Active Member
Licensed User
Longtime User
Hallo

> Welchen Wert hat DBFileName, Mystery5.db oder Mystery4.db ?
Dim DBFileName As String : DBFileName = "Mystery5.db"
Was meinst du mit Welchen Wert hat Mystery5.db und Mystery4.db ?

> Hast Du auch den Wert von NumberOfColumns geändert ?
_ Hast du die Arrays ColumnWidth(i), ColumnWidth_1(i) usw. mit dem neuen NumberOfColumns Wert deklariert ?
Natürlich. Arrays kannte ich schon vor 1987.

>Wenn Deine neue Datenbank die neuen Spalten schon beinhaltet brauchst Du die beiden Zeilen von Paulsche nicht.
Wir drehren uns hier im Kreis. Auf dem PC sind die Daten vorhanden. Jedes mal wenn ich die Datei mit SQLite öffne ist alles OK. Auf dem Handy komme ich nicht ran. Die Verzeichnisse die angegeben werden existieren nicht. Ich habe überall wo eine alte Mystery4.db war eine neue Mystery5.db hinkopiert. Ob ich alle verzeichnisse mit dem Explorer gefunden habe weiß ich nicht. Es musss doch eine Möglichkeit geben die Datei an den Punkt zu kopieren den das Programm braucht.

Ich wollte gerade das komplette Programm als ZIP exportieren bekomme aber die Fehlermeldung: An error occured, size was 0, but I expected 131072.

Es ist aber die gleiche Datei wie in meinem alten Thead "scrollview mit Daten füllen". Ich habe nur in anderen Activitys programmiert. Das Activity "Main" ist immer noch das gleiche. Du hattest mir damls eine geänderte Datei zukommen lassen.

Martin
 

Paulsche

Well-Known Member
Licensed User
Longtime User
Hallo paulsche

Reden wir von den selben Dingen ?

Ich habe eine SQL-Datei mit der Tabelle gccode. Hier habe ich folgende Felder:
ColumnName(0) = "id"
ColumnName(1) = "gccode"
ColumnName(2) = "nord1"
ColumnName(3) = "nord2"
ColumnName(4) = "nord3"
ColumnName(5) = "ost1"
ColumnName(6) = "ost2"
ColumnName(7) = "ost3"
ColumnName(8) = "infofeld"
ColumnName(9) = "hint"
ColumnName(10) = "name"
ColumnName(11) = "gelaende"
ColumnName(12) = "groesse"
Das klappt und funktioniert. Nun möchte ich einmalig folgende Felder hinzufügen:
ColumnName(13) = "art"
ColumnName(14) = "schwierig"
ColumnName(15) = "ort"
ColumnName(16) = "update"
ColumnName(17) = "gefunden"
ColumnName(18) = "info1"
ColumnName(19) = "info2"
Nur einmal und nicht immer wieder.
Martin

Ich frage einfach die Anzahl der Felder ab, in Deinem Fall
If xxx.ColumnCount =13 then .... (Felder hinzufügen)
Beim nächsten Starten wird dies nicht mehr ausgeführt, da
ColumnCount nun =20 ist.
 

tudorf

Active Member
Licensed User
Longtime User
Hallo
So ich habe die Sache geändert. Ich erstelle die SQL-Datei per Programm. Beim Auslesen erhalte ich auch die Anzahl der Felder.

File.Delete(DBFileDir, DBFileName)
SQL1.Initialize(DBFileDir, DBFileName, True)

Dim neu As String
neu = "CREATE TABLE gcneu (id INTEGER PRIMARY KEY , gccode CHAR(10), nord1 Char (1))"
SQL1.ExecNonQuery(neu)

If FirstTime Then
If File.Exists(DBFileDir, DBFileName) = False Then
Msgbox("Datei muss kopiert werden","")
Else
Msgbox("Datei ist vorhanden","")
End If
RowIDs.Initialize
SQL1.Initialize(DBFileDir, DBFileName, True)
End If

Dim Zahl As Cursor
Zahl = SQL1.ExecQuery("select * from gcneu")
Msgbox(Zahl.ColumnCount,"Anzahl")

' Testweise einen Datensatz anhängen
Dim txt As String
txt="INSERT INTO gcneu VALUES (NULL , 'test1','M')"
SQL1.ExecNonQuery(txt)

Martin
 
Top