SQLite mit Delphi
Der SQLite-Wrapper für Delphi
Wenn man sich den SQLite4Delphi Wrapper von Tim Anderson noch nicht heruntergeladen hat, dann sollte man das jetzt nachholen. Das zip-Archiv beinhaltet auch eine Demo-Anwendung TestSQLite.dpr, die wir gleich unter die Lupe nehmen werden. Zunächst jedoch die wichtigsten Dinge zur Arbeit mit SQLite und dem Delphi-Wrapper.
Datenbankverbindung herstellen und trennen
Wie bereits erwähnt, speichert SQLite seine Daten in einer Datei. Für diese müssen wir einen Dateinamen vorgeben. Der Einfachheit halber nennen wir sie „starter.db“ und legen sie direkt neben unsere Anwendung. (Bitte beachten: Sofern sich die Anwendung im Programmeverzeichnis von Windows befindet, ist das ohne Administratorrechte nicht möglich! In diesem Fall muss ein anderes Verzeichnis verwendet werden.)
uses SQLiteTable3; var databaseFile: String; database: TSQLiteDatabase; begin databaseFile := ExtractFilePath(Application.ExeName) + ‘starter.db’; database := TSQLiteDatabase.Create(datbaseFile); try ... finally database.Free; end; end;
Dreh- und Angelpunkt der SQLite-Anbindung ist die Klasse TSQLiteDatabase. Sie wird mit einem Dateinamen initialisiert. Da das Objekt am Ende wieder freigegeben werden muss, wird in obigem Beispiel der eigentliche Code zwischen try und finally ausgeführt – anstelle der drei Punkte.
Datensatz abfragen
Abfragen richten sich an eine bestimmte Tabelle. Möchte man z.B. aus der oben bereits verwendeten Tabelle „artikel“ den Artikel mit der ID 4711 abfragen, verwendet man folgenden Code:
var table: TSQLiteTable; bezeichnung: String; ... table := database.GetTable(‘SELECT * FROM artikel WHERE id = 4711‘);
Auf die einzelnen Felder kann man dann über die entsprechenden Methode von table zugreifen:
bezeichnung := table.FieldAsString(table.FieldIndex(‘bezeichnung‘));
Zu beachten ist hier: Die Methoden FieldAsString, FieldAsInteger, FieldAsDouble usw. erwarten als Parameter nicht den Namen der Spalte, sondern deren Index. Diesen wiederum erhält man über die Methode FieldIndex.
Abfragen mehrerer Datensätze
In obigem Beispiel wird als Ergebnis exakt ein Datensatz erwartet. Natürlich gibt es aber auch Abfragen, die eine ganze Liste an Datensätzen liefern. Z.B. alle Artikel, die teurer sind als 20 EUR:
table := database.GetTable(‘SELECT * FROM artikel WHERE preis > 20‘); for i := 0 to table.Count - 1 do begin bezeichnung := table.FieldAsString(table.FieldIndex(‘bezeichnung‘)); if not table.EOF then table.Next; end;
Die Methode Count liefert die Anzahl der gefundenen Datensätze. Mit den FieldAs-Methoden greift man immer auf die Spalten des aktuellen Datensatzes zu. Zum nächsten Datensatz wechselt man über den Aufruf Next, zurück geht es mit Previous. Next sollte man natürlich nur aufrufen, wenn man sich nicht schon auf dem letzten Datensatz befindet. Deshalb wird das in obigem Beispiel zuerst geprüft (EOF gibt true zurück, wenn wir am Ende sind).
Demoanwendung
Wie bereits erwähnt, enthält der Wrapper eine kleine Beispiel-Anwendung. Diese macht nicht viel mehr als eine kleine Tabelle anzulegen und einen Datensatz anzuzeigen. Diese Demoanwendung wird nun etwas genauer unter die Lupe genommen.
Im OnClick-Event des Buttons btnTest spielt sich der interessante Teil ab. Zuerst wird mittels TSQLiteDatabase.Create(slDBPath); eine neue SQLite-Datenbank im Programmordner angelegt. Existiert die angegebene Datei bereits, wird sie als Datenbank geöffnet. In den darauf folgenden Zeilen wird die Tabelle testTable, sofern sie existiert gelöscht (DROP TABLE testtable) und dann komplett neu angelegt. Dabei ist die Struktur des CREATE TABLE-Befehls zu sehen.
CREATE TABLE testtable ([ID] INTEGER PRIMARY KEY, [OtherID] INTEGER NULL, [Name] VARCHAR (255), [Number] FLOAT, [notes] BLOB, [picture] BLOB COLLATE NOCASE);
In eckigen Klammern (das ist nicht SQL-Standard!) steht hier der Feldname gefolgt vom Typ des Feldes (INTEGER, FLOAT, VARCHAR = Zeichenkette, BLOB). Das Feld [ID] wird zudem als Primärschlüssel (PRIMARY KEY) definiert. Das bewirkt, dass kein Datensatz mit derselben ID in der Tabelle vorkommen wird. Wird ein neuer Datensatz hinzugefügt, bekommt er die nächsthöhere Zahl als ID zugewiesen. Der Typ BLOB (binary large object) ist für die Speicherung großer Datenmengen geeignet. Die Daten werden unverändert in der Datenbank abgelegt, was sie für das Speichern von Bilddaten nutzbar macht.
Mit der Zeile
sldb.execsql(sSQL);
wird der Befehl ausgeführt.
Mit der Zeile
sldb.execsql('CREATE INDEX TestTableName ON [testtable]([Name]);');
wird ein Index auf das Feld „Name“ gelegt. Durch einen Index wird die Suche und das Sortieren nach bestimmten Feldern beschleunigt.
Die darauf folgenden Befehle werden zu einer Transaktion zusammengefasst. Das bedeutet, es werden alle Befehle zwischengespeichert und erst mit dem Aufruf von
sldb.Commit;
ausgeführt. Der Sinn einer Transaktion liegt darin, dass alle Befehle darin ausgeführt werden oder gar keiner. D.h. wenn bei einem Befehl innerhalb einer Transaktion ein Fehler auftritt, werden die davor kommenden rückgängig gemacht (Rollback).
Da jetzt Daten in der Datenbank abgelegt sind, können sie auch ausgelesen werden. Genau das machen die Zeilen
//query the data sltb := slDb.GetTable('SELECT * FROM testtable'); try if sltb.Count > 0 then begin //display first row ebName.Text := sltb.FieldAsString(sltb.FieldIndex['Name']); ebID.Text := inttostr(sltb.FieldAsInteger(sltb.FieldIndex['ID'])); ebNumber.Text := floattostr( sltb.FieldAsDouble(sltb.FieldIndex['Number'])); Notes := sltb.FieldAsBlobText(sltb.FieldIndex['Notes']); memNotes.Text := notes; end; finally sltb.Free; end;
Zuerst wird eine SELECT-Anfrage gestellt und das Ergebnis (hier nur der erste Datensatz) dann auf dem Formular angezeigt. Um die Daten in verwendbaren Datentypen zu bekommen existieren die Methoden FieldAsString, FieldAsInteger, FieldAsDouble und FieldAsBlobText. Wie man an obigen Code-Zeilen sehr schön sehen kann, wird mit dem Feldnamen auf die Daten zugegriffen (FieldIndex[‚Name‘]).
Für die weitere Vertiefung in die Thematik SQLite mit Delphi ist die SQLite-Homepage eine gute Anlaufstelle. Dort findet man alle Neuerungen und Möglichkeiten, die SQLite anbietet.