SQLite3 mit Delphi und dbExpress
SQLite spezielle Anwendungsbeispiele
SQLite-Datensätze im DBGrid
Download Delphi XE3 Quellcode ropDelphiSQLiteDBGrid
Um eine SQLite-Datenbank mit einem DBGrid zu verbinden, werden verschiedene Komponenten benötigt:
TSQLConnection (dbExpress) -> TSQLDataSet (dbExpress) -> TDataSetProvider (Data Access)-> ClientDataSet (Data Access)-> TDataSource (Data Access) -> TDBGrid (Data Controls)
Siehe grafische Darstellung (startet mit SQLConnection1 … DataSource1)
Hinweise
- DBGrid1 ist mit DataSource1 verbunden.
- DBNavigator1 ist auch mit DataSource1 verbunden.
- Änderungen können im DBGrid1 direkt oder mittels DBNavigator1 vorgenommen werden.
- Wenn die Anwendungen verlassen werden, müssen die Daten aus dem DBGrid1 in die SQLite Datenbank gespeichert werden. Hierzu wird ClientDataSet1.ApplyUpdates verwendet.
Ausschnitte aus einer Beispielanwendung
Verwendet wird die SQLite-Datenbank BUECHER.DB mit den Tabellen Buecher und Autoren.
Verbindung mit der SQLite Datenbank herstellen:
Procedure TfrmMain.ActionDatabaseConnectExecute(Sender: TObject); Begin Try SQLDataset1.Close; SQLConnection1.Close; SQLConnection1.Params.Values['Database'] := 'buecher.db'; //ggf. Pfadangabe SQLConnection1.Params.Values['FailIfMissing'] := 'False'; SQLConnection1.Open; Except On E: EDatabaseError Do ShowMessage(E.Message); End; End;
Daten selektieren und im DBGrid darstellen:
Procedure TfrmMain.ActionTableGetDataExecute(Sender: TObject); // Daten aus der SQLite Tabelle Buecher und Autoren lesen und im DBGrid anzeigen // Verwendet wird ein SQL Select JOIN Befehl. Begin Try ClientDataSet1.Active := False; SQLDataset1.CommandText := 'SELECT Buecher.BuchID,Buecher.Titel,Buecher.AutorID, Autoren.Name, Buecher.ISBN FROM Autoren, Buecher WHERE Autoren.AutorID=Buecher.AutorID;'; SQLDataset1.Open; // Clientdataset aktivieren um die Daten im DBGrid anzuzeigen ClientDataSet1.Active := True; Except On E: EDatabaseError Do ShowMessage(E.Message); End; End;
Ergebnis
Hinweise
- Bevor der SQLDataset1.CommandText ausgeführt wird, muss zuerst das SQLDataSet deaktiviert werden.
- Im DBGrid wird das Ergebnis des SQL-Befehls SELECT gezeigt. Es können auch selektive Ergebnisse als SQLDataset1.CommandText gezeigt werden. Vgl. ‚SELECT * FROM Buecher WHERE BuchID < 3;‘ oder ‚SELECT * FROM Buecher ORDER BY ISBN DESC‘; oder JOIN ‚SELECT Autoren.Name,Buecher.Titel FROM Autoren, Buecher WHERE Autoren.AutorID=Buecher.AutorID;‘
Daten in einen DBGrid mittels DBNavigator einfügen – spezieller Fall AutoInc Feld
Wird ein AutoInc-Feld benutzt, dann muss dieses Feld mit einem Wert belegt werden, bevor der Datensatz im ClientDataSet gespeichert wird. Unter Verwendung eines DBNavigators, macht SQLite das nicht automatisch.
Beispiel Tabelle Buecher, Feld BuchId (AutoInc)
Definiert wird eine Prozedur ClientDataSetBeforPost, die eine Funktion GetNextBuchID verwendet.
Procedure TfrmMain.ClientDataSet1BeforePost(DataSet: TDataSet); Begin // Feld BuchID auf NULL prüfen und den nächst höheren Wert zuweisen. If TClientDataSet(DataSet).FieldByName('BuchID').IsNull Then TClientDataSet(DataSet).FieldByName('BuchID').Value := GetNextBuchID; End; Function TfrmMain.GetNextBuchID: Integer; // Nächst höheren Wert für Feld BuchID definieren Begin SQLDataset1.Close; SQLDataset1.CommandText := 'SELECT Max(BuchID) FROM Buecher;'; SQLDataset1.Open; Result := SQLDataset1.Fields[0].AsInteger + 1; SQLDataset1.Close; End;
Daten aus dem ClientDataSet in der SQLite-Datenbank speichern
Im DBGrid können Daten bearbeitet werden. Da diese im Speicher verbleiben, müssen Änderungen vom ClientDataSet auch in der SQLite Datenbank gespeichert werden.
Verwende hierzu ClientDataSet.ApplyUpdates.
Procedure TfrmMain.ClientDataSet1BeforeRefresh(DataSet: TDataSet); Begin If DataSet = NIL Then Abort; If TClientDataSet(DataSet).Active = False Then Abort; If TClientDataSet(DataSet).ChangeCount > 0 Then begin TClientDataSet(DataSet).ApplyUpdates(-1); End; End;
Hinweis: Um sicherzustellen, dass Änderungen auch beim Verlassen der Anwendung in der SQLite-Datenbank gespeichert werden, ClienDataSet1BeforeRefresh() in FormClose aufrufen.
Procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction); Begin ClientDataSet1BeforeRefresh(ClientDataSet1); End;
SQLite BLOBs verwenden
Download Delphi XE3 Quellcode ropDelphiSQLiteBlob.
Tabelle mit BLOB-Spalte definieren:
Try SQLConnection.ExecuteDirect('CREATE TABLE images (' + 'id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE,' + 'title TEXT NOT NULL, ' + 'image BLOB NOT NULL)'); Except On E: EDatabaseError Do ShowMessage(E.Message); End;
BLOB in Tabelle images Feld image laden:
Procedure TfrmMain.InsertPicture(Sender: TObject; sTitle, sImagePath: String); // Titel und Image in der SQL-Tabelle images laden Var streamImage: TMemoryStream; // Stream um Datei Image zu speichern LTransaction: TDBXTransaction; // SQLConnection Transaktion LDBXCmd: TSQLQuery; // SQL-Query LParam: TParam; // Parameter für SQL-Query LSQL: String; // SQL-Befehl Begin // SQL-Befehl INSERT zusammenstellen - achte auf "value ?" für image LSQL := 'INSERT INTO images(title, image) VALUES("' + sTitle + '", ?)'; // Stream erstellen - LoadFromFile kann noch erweitert werden mit z.B. // If FileExists... streamImage := TMemoryStream.Create; streamImage.LoadFromFile(sImagePath); // Transaktion eröffnen LTransaction := SQLConnection.BeginTransaction; // Query Befehl zusammenstellen LDBXCmd := TSQLQuery.Create(SQLConnection); Try Try LDBXCmd.SQLConnection := SQLConnection; LDBXCmd.SQL.Text := LSQL; LParam := LDBXCmd.Params.CreateParam(ftBlob, 'Picture', ptInput); LParam.LoadFromStream(streamImage, ftBlob); LDBXCmd.ExecSQL; Except On E: Exception Do SQLConnection.RollbackFreeAndNil(LTransaction); End; SQLConnection.CommitFreeAndNil(LTransaction); Finally LDBXCmd.Free; End; End;
Aufrufbeispiel Bitmap m.bmp aus dem Anwendungs-/Projektverzeichnis in der Tabelle laden
InsertPicture(Sender, 'M', ExtractFilePath(Application.ExeName) + 'm.bmp');
Inhalt BLOB in Formular TImage zeigen:
Procedure TfrmMain.LoadPicture(Sender: TObject; sTitle: String); // Titel und Bild in Label und Image laden Var LSQL: String; // SQL-Befehl DS: TDataSet; // Resultat SQL-Befehl Select BlobField: TField; // Blobfeld benötigt für BlobStream BS: TStream; // BS Blobstream BM: TBitMap; // Bitmap im Image laden Begin // Select Befehl nach Titel LSQL := 'SELECT * FROM images WHERE title = "' + sTitle + '"'; Try // SQL-Befehl ausführen und Ergebnis in DS speichern DS := NIL; SQLConnection.Execute(LSQL, NIL, DS); // Ergebnis lesen und Inhalt Label, BlobField, Bitmap und Image zuweisen If DS NIL Then Begin lblTitle.Caption := DS.FieldByName('title').AsString; Blobfield := DS.FieldbyName('image'); BS := DS.CreateBlobStream(BlobField, bmReadWrite); BM := TBitMap.Create; BM.LoadFromStream(BS); Image1.Picture.Bitmap := BM; End; Except On E: Exception Do ShowMessage(E.Message); End; End;
SQLite SQL-Befehle direkt ausführen
Download Delphi XE3 Quellcode ropSQLiteIt
Beispiel wie ropSQLiteIt verwendet werden kann:
Eine Datenbank Logs.db mit Logging Tabelle Logs erstellen und verwenden.
1. Datei > Datenbank öffnen (Strg-O) > Dateiname logs.db
3. Tabelle Logs erstellen:
CREATE TABLE logs (id INTEGER PRIMARY KEY AUTOINCREMENT, logtype TEXT, logname TEXT, logmessage TEXT, logtime DATETIME);
4. Testdaten hinzufügen:
INSERT INTO logs (id,logtype,logname,logmessage,logtime) VALUES (NULL, 'TestLog1', 'TestEvent 1', 'Testaktivität 1', datetime('now'));
INSERT INTO logs (id,logtype,logname,logmessage,logtime) VALUES (NULL, 'TestLog2', 'TestEvent 2', 'Testaktivität 2', datetime('now'));
INSERT INTO logs (id,logtype,logname,logmessage,logtime) VALUES (NULL, 'TestLog1', 'TestEvent 3', 'Testaktivität 3', datetime('now'));
5. Testdaten zeigen:
SELECT * FROM logs;
SELECT * FROM logs WHERE strftime('%s', 'now')-strftime('%s', logtime) < 3600;
SELECT * FROM logs WHERE logtype = "TestLog1";
SELECT logtype, COUNT(logtype) FROM logs GROUP BY logtype;
6. Testdaten löschen:
DELETE FROM logs;
Ergebnis
SQLite-Tabelle für Einstellungen verwenden
Eine SQLite-Tabelle kann auch verwendet werden, um Einstellungen einer Anwendung zu speichern oder zu lesen. Der Tabellenaufbau ist identisch mit der einer Ini-Datei: [SEKTION] Schlüssel=Wert.
SQL-Tabelle System definieren und erstellen:
CREATE TABLE System (
ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE,
syssection TEXT,
syskey TEXT,
sysvalue TEXT);
Funktionen definieren um Werte zu speichern / lesen:
Function SQLSystemRead(sSection, sKey, sDefault : String): String; Var LSQL: String; DS: TDataSet; Begin Result := sDefault; Try LSQL := 'SELECT sysvalue FROM System WHERE ' + 'syssection=' + '''' + sSection + '''' + ' AND ' + 'syskey=' + '''' + sKey + '''' + ''; SQLConnection.Execute(LSQL, NIL, DS); Result := DS.FieldByName('sysvalue').AsString; If Result = '' Then Result := sDefault; Except On E: EDatabaseError Do ShowMessage(E.Message); End; End; Function SQLSystemUpdate(sSection, sKey, sValue: String): Boolean; Var LSQL: String; DS: TDataSet; Begin Result := False; Try LSQL := 'SELECT sysvalue FROM System WHERE ' + 'syssection=' + '''' + sSection + '''' + ' AND ' + 'syskey=' + '''' + sKey + '''' + ''; SQLConnection.Execute(LSQL, NIL, DS); If DS.FieldByName('sysvalue').AsString = '' Then Begin LSQL := 'INSERT INTO system (syssection, syskey, sysvalue) VALUES (' + '''' + sSection + '''' + ', ' + '''' + sKey + '''' + ', ' + '''' + sValue + '''' + ')'; SQLConnection.Execute(LSQL, NIL); Result := True; End Else Begin LSQL := 'UPDATE system ' + 'SET ' + 'syssection=' + '''' + sSection + '''' + ', ' + 'syskey=' + '''' + sKey + '''' + ', ' + 'sysvalue=' + '''' + sValue + '''' + ' WHERE ' + 'syssection=' + '''' + sSection + '''' + ' AND ' + 'syskey=' + '''' + sKey + '''' + ''; SQLConnection.Execute(LSQL, NIL); End; Except On E: EDatabaseError Do ShowMessage(E.Message); End; End;
Anwenden z.B. in FormCreate, FormClose
Procedure TfrmMain.FormCreate = Form Top Position lesen und setzen
Top := StrToInt(SQLSystemRead('MAINPOSITION', 'Top', '100'));
Procedure TfrmMain.FormClose = Form Top Position speichern
SQLSystemUpdate('MAINPOSITION', 'Top', IntToStr(Top));