Home » Tutorials » Datenbanken » SQLite3 mit Delphi und dbExpress

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));