Dieses Tutorial behandelt die SQL Library und ihre Nutzung mit Basic4android.
Es gibt viele allgemeine SQL-Tutorials, die die eigentliche SQL Sprache behandeln. Wenn Sie nicht mit SQL vertraut sind, empfehlen wir, mit einem Lernprogramm wie diesem zu starten.
SQL Introduction leider in Englisch.
Der Sourcecode des Beispielprogramms befindet sich am Ende.
Das Englische Originaltutorial.
Android nutzt SQLite, das eine Open-Source-SQL-Implementierung ist.
Jede Implementierung hat einige Nuancen. Die beiden folgenden Links behandeln wichtige Informationen zu SQLite.
SQLite Syntax: Query Language Understood by SQLite
SQLite-Datentypen: Datatypes In SQLite Version 3
SQL in Basic4android
Der erste Schritt ist, eine Referenz auf die SQL-Library hinzuzufügen. Dies macht man indem man SQL im Library Tab unten rechts im IDE anhakt.
Es gibt zwei Types in dieser Library.
Ein SQL Objekt das den Zugriff auf die Datenbank ermöglicht.
Ein Cursor Objekt das die Bearbeitung der Ergebnisse von Anfragen ermöglicht.
Normalerweise muß man das SQL Objekt als globales Prozessobjekt deklarieren. Auf diese Weise wird es aktiv bleiben, auch wenn die Activity wieder neu erstellt (resumed) wird.
SQLite speichert die Datenbank in einer einzigen Datei.
Wenn wir das SQL Objekt initialisieren geben wir den Ordner und den Namen der Datenbankdatei ein (die erstellt werden kann, wenn nötigt).
Das SQL1 Objekt wird nur einmal initialisiert, wenn der Prozess beginnt.
In unserem Fall erstellen wir es in der SD-Karte. Der letzte Parameter (CreateIfNecessary) ist True, also wird die Datei erstellt, wenn sie noch nicht vorhanden ist.
Es gibt drei verschiedene Methoden, die SQL-Anweisungen ausführen.
ExecNonQuery – Führt eine Schreibanweisung durch, ohne Rückgabewert. Zum Beispiel: INSERT, UPDATE or CREATE TABLE.
ExecQuery - Führt eine Anfrageanweisung durch mit einem Cursor Objekt als Rückgabewert das zur Behandlung des Resultates verwendet wird.
ExecQuerySingleResult - Führt eine Anfrageanweisung durch und gibt den Wert der ersten Spalte in der ersten Zeile des Resultates zurück. Diese Methode ist ein Kürzel für die ExecQuery Anweisung und das Lesen mit dem Cursor Objekt.
Wir werden das folgende Beispiel erklären:
Der Obige Code löscht zuerst die zwei Tabellen falls sie existieren und erstellt sie wieder neu.
In diesem Code werden zwei Zeilen hinzugefügt. SQL.ExecNonQuery2 enthält zwei Parameter. Der erste Parameter ist die Anweisung zwischen Anführungszeichen. Die Fragezeichen werden dann durch die Werte des zweiten List Parameters ersetzt. Die Liste kann entweder Zahlen, Strings oder Bytearrays (blobs) enthalten.
Arrays werden implizit in Listen konvertiert deshalb benutzen wir das Schlüsselwort Array um ein Objektarray zu erstellen anstatt eine Liste zu erstellen.
Dieser Code verwendet einen Cursor um die beiden Zeilen zu lesen, die zuvor eingefügt wurden. SQL.ExecQuery gibt ein Cursor-Objekt zurück.
Dann durchlaufen wir in der For-Next Schlaufe alle Ergebnisse.
Beachten Sie, daß wir vor dem Lesen der Werte aus dem Cursor dessen Position eingestellt haben (die aktuelle Zeile).
Dieser Code ist ein Beispiel für das Hinzufügen vieler Zeilen. Intern wird nach jeder Schreibfunktion ein Schloß erstellt.
Durch die explizite Erstellung der Transaktion mit BeginTransaction wird das Schloß nur einmal erstellt.
Der obige Code, auf einem echten Gerät ausgeführt, dauerte weniger als eine halbe Sekunde.
Ohne den BeginTransaction / EndTransaction Block dauerte es etwa 70 Sekunden.
Ein Transaktionsblock kann auch verwendet werden um sicherzustellen, daß eine Reihe von Änderungen erfolgreich durchgeführt wurde. Entweder werden alle Änderungen vorgenommen oder keine.
Durch den Aufruf SQL.TransactionSuccessful erklären wir die Transaktion als erfolgreich. Wenn wir diese Zeile weglassen würden, würden alle 500 INSERTS ignoriert werden.
Es ist sehr wichtig, am Ende EndTransaction anzufügen.
Ein 'Standard' Transaktionblock sieht wie folgend aus:
Beachten Sie, daß die Verwendung von Transaktionen nur für Schreiboperationen relevant ist.
Blobs
Die letzten beiden Methoden schreiben eine Bilddatei in die Datenbank und lesen sie dann zurück und setzten das Bild als Hintergrundsbild für die Acivity.
Hier benutzen wir einen speziellen OutputStream Type, der in ein dynamisches Byte Array schreibt.
File.Copy2 kopiert alle verfügbaren Daten aus dem InputStream in den OutputStream.
Dann wird das Bytes Array in die Datenbank geschrieben.
Mit Cursor.GetBlob holen wir das zuvor gespeicherte Bild zurück.
Jetzt benutzen wir einen Buffer und einen InputStream, die das Bild laden.
Und zuletzt wird das Bild als Activity Hintergrunbild gesetzt.
Der Sourcecode des Beispielprogramms :
Es gibt viele allgemeine SQL-Tutorials, die die eigentliche SQL Sprache behandeln. Wenn Sie nicht mit SQL vertraut sind, empfehlen wir, mit einem Lernprogramm wie diesem zu starten.
SQL Introduction leider in Englisch.
Der Sourcecode des Beispielprogramms befindet sich am Ende.
Das Englische Originaltutorial.
Android nutzt SQLite, das eine Open-Source-SQL-Implementierung ist.
Jede Implementierung hat einige Nuancen. Die beiden folgenden Links behandeln wichtige Informationen zu SQLite.
SQLite Syntax: Query Language Understood by SQLite
SQLite-Datentypen: Datatypes In SQLite Version 3
SQL in Basic4android
Der erste Schritt ist, eine Referenz auf die SQL-Library hinzuzufügen. Dies macht man indem man SQL im Library Tab unten rechts im IDE anhakt.
Es gibt zwei Types in dieser Library.
Ein SQL Objekt das den Zugriff auf die Datenbank ermöglicht.
Ein Cursor Objekt das die Bearbeitung der Ergebnisse von Anfragen ermöglicht.
Normalerweise muß man das SQL Objekt als globales Prozessobjekt deklarieren. Auf diese Weise wird es aktiv bleiben, auch wenn die Activity wieder neu erstellt (resumed) wird.
SQLite speichert die Datenbank in einer einzigen Datei.
Wenn wir das SQL Objekt initialisieren geben wir den Ordner und den Namen der Datenbankdatei ein (die erstellt werden kann, wenn nötigt).
B4X:
Sub Process_Globals
Dim SQL1 As SQL
End Sub
Sub Globals
End Sub
Sub Activity_Create(FirstTime As Boolean)
If FirstTime Then
SQL1.Initialize(File.DirDefaultExternal, "test1.db", True)
End If
CreateTables
FillSimpleData
LogTable1
InsertManyRows
Log("Number of rows = " & SQL1.ExecQuerySingleResult("SELECT count(*) FROM table1"))
InsertBlob 'stores an image in the database.
ReadBlob 'load the image from the database and displays it.
End Sub
In unserem Fall erstellen wir es in der SD-Karte. Der letzte Parameter (CreateIfNecessary) ist True, also wird die Datei erstellt, wenn sie noch nicht vorhanden ist.
Es gibt drei verschiedene Methoden, die SQL-Anweisungen ausführen.
ExecNonQuery – Führt eine Schreibanweisung durch, ohne Rückgabewert. Zum Beispiel: INSERT, UPDATE or CREATE TABLE.
ExecQuery - Führt eine Anfrageanweisung durch mit einem Cursor Objekt als Rückgabewert das zur Behandlung des Resultates verwendet wird.
ExecQuerySingleResult - Führt eine Anfrageanweisung durch und gibt den Wert der ersten Spalte in der ersten Zeile des Resultates zurück. Diese Methode ist ein Kürzel für die ExecQuery Anweisung und das Lesen mit dem Cursor Objekt.
Wir werden das folgende Beispiel erklären:
B4X:
Sub CreateTables
SQL1.ExecNonQuery("DROP TABLE IF EXISTS table1")
SQL1.ExecNonQuery("DROP TABLE IF EXISTS table2")
SQL1.ExecNonQuery("CREATE TABLE table1 (col1 TEXT , col2 INTEGER, col3 INTEGER)")
SQL1.ExecNonQuery("CREATE TABLE table2 (name TEXT, image BLOB)")
End Sub
B4X:
Sub FillSimpleData
SQL1.ExecNonQuery("INSERT INTO table1 VALUES('abc', 1, 2)")
SQL1.ExecNonQuery2("INSERT INTO table1 VALUES(?, ?, ?)", Array As Object("def", 3, 4))
End Sub
Arrays werden implizit in Listen konvertiert deshalb benutzen wir das Schlüsselwort Array um ein Objektarray zu erstellen anstatt eine Liste zu erstellen.
B4X:
Sub LogTable1
Dim Cursor1 As Cursor
Cursor1 = SQL1.ExecQuery("SELECT col1, col2, col3 FROM table1")
For i = 0 To Cursor1.RowCount - 1
Cursor1.Position = i
Log("************************")
Log(Cursor1.GetString("col1"))
Log(Cursor1.GetInt("col2"))
Log(Cursor1.GetInt("col3"))
Next
Cursor1.Close
End Sub
Dann durchlaufen wir in der For-Next Schlaufe alle Ergebnisse.
Beachten Sie, daß wir vor dem Lesen der Werte aus dem Cursor dessen Position eingestellt haben (die aktuelle Zeile).
B4X:
Sub InsertManyRows
SQL1.BeginTransaction
Try
For i = 1 To 500
SQL1.ExecNonQuery2("INSERT INTO table1 VALUES ('def', ?, ?)", Array As Object(i, i))
Next
SQL1.TransactionSuccessful
Catch
Log(LastException.Message)
End Try
SQL1.EndTransaction
End Sub
Durch die explizite Erstellung der Transaktion mit BeginTransaction wird das Schloß nur einmal erstellt.
Der obige Code, auf einem echten Gerät ausgeführt, dauerte weniger als eine halbe Sekunde.
Ohne den BeginTransaction / EndTransaction Block dauerte es etwa 70 Sekunden.
Ein Transaktionsblock kann auch verwendet werden um sicherzustellen, daß eine Reihe von Änderungen erfolgreich durchgeführt wurde. Entweder werden alle Änderungen vorgenommen oder keine.
Durch den Aufruf SQL.TransactionSuccessful erklären wir die Transaktion als erfolgreich. Wenn wir diese Zeile weglassen würden, würden alle 500 INSERTS ignoriert werden.
Es ist sehr wichtig, am Ende EndTransaction anzufügen.
Ein 'Standard' Transaktionblock sieht wie folgend aus:
B4X:
SQL1.BeginTransaction
Try
'Execute the sql statements.
SQL.TransactionSuccessful
Catch
'the transaction will be cancelled
End Try
SQL.EndTransaction
Blobs
Die letzten beiden Methoden schreiben eine Bilddatei in die Datenbank und lesen sie dann zurück und setzten das Bild als Hintergrundsbild für die Acivity.
B4X:
Sub InsertBlob
'convert the image file to a bytes array
Dim InputStream1 As InputStream
InputStream1 = File.OpenInput(File.DirAssets, "smiley.gif")
Dim OutputStream1 As OutputStream
OutputStream1.InitializeToBytesArray(1000)
File.Copy2(InputStream1, OutputStream1)
Dim Buffer() As Byte 'declares an empty array
Buffer = OutputStream1.ToBytesArray
'write the image to the database
SQL1.ExecNonQuery2("INSERT INTO table2 VALUES('smiley', ?)", Array As Object(Buffer))
End Sub
File.Copy2 kopiert alle verfügbaren Daten aus dem InputStream in den OutputStream.
Dann wird das Bytes Array in die Datenbank geschrieben.
B4X:
Sub ReadBlob
Dim Cursor1 As Cursor
'Using ExecQuery2 is safer as it escapes special characters automatically.
'In this case it doesn't really matter.
Cursor1 = SQL1.ExecQuery2("SELECT image FROM table2 WHERE name = ?", Array As String("smiley"))
Cursor1.Position = 0
Dim Buffer() As Byte 'declare an empty byte array
Buffer = Cursor1.GetBlob("image")
Dim InputStream1 As InputStream
InputStream1.InitializeFromBytesArray(Buffer, 0, Buffer.Length)
Dim Bitmap1 As Bitmap
Bitmap1.Initialize2(InputStream1)
InputStream1.Close
Activity.SetBackgroundImage(Bitmap1)
End Sub
Jetzt benutzen wir einen Buffer und einen InputStream, die das Bild laden.
Und zuletzt wird das Bild als Activity Hintergrunbild gesetzt.
Der Sourcecode des Beispielprogramms :
Attachments
Last edited: