Sign in Join
Wiki copytemporary

Database tutorial SQLdb1/de: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11## Einleitung
22
33Dieses Tutorial hat das Ziel, die Verwendung des [[SQLdb Package|SQLdb Packages]] anhand praktischer Beispiele zu demonstrieren. Es richtet sich vor allem an Einsteiger. Wer nach Grundlageninformationen über Datenbanken und SQL sucht, dem seien die einschlägigen Bücher empfohlen. Für das Tutorial greife ich auf Firebird mit der Beispieldatenbank employee.fdb zurück.
44
55Bedanken möchte ich mich bei Joost und Michael, ohne deren Hilfe das Tutorial wahrscheinlich nicht zustande gekommen wäre.
66
77## Voraussetzungen
88
99Für dieses Tutorial sollten sie möglichst eine aktuelle Lazarus Version verwenden (mit FPC 2.6.2 oder höher). Sollte das SQLdb Package noch nicht installiert sein, dann holen sie das jetzt nach (Package -\> Installierte Packages einrichten ... -\> SQLDBLaz 1.0.2). Außerdem wird [Firebird](http://sourceforge.net/project/showfiles.php?group_id=9028) (möglichst Version 2.5 oder höher) benötigt. Die Beispiele gehen davon aus, dass die Standardvorgaben (SYSDBA und masterkey) nicht verändert wurden.
1010
1111## Beispiel 1
1212
1313Starten sie ein neues Projekt in Lazarus. Für den Zugriff auf die Datenbank benötigen wir je eine *TIBConnection*, *TSQLTransaction* und *[[Working With TSQLQuery|TSQLQuery]]* von der Seite 'SQLdb' in der Komponentenpalette. Die erste Komponente ist spezifisch für den Zugriff auf Firebird-Datenbanken. Die beiden anderen Komponenten kommen bei allen Datenbanken zum Einsatz, auf die sie mit SQLdb zugreifen können. Für die Anzeige der Daten verwenden wir eine *TDBGrid* Komponente, die sie auf der Seite 'Data Controls' finden. Für die Verbindung mit den Datenbankkomponenten benötigen wir noch eine *TDatasource* Komponente von der Seite 'Data Access'. Zum Auslösen der Aktionen verwenden wir einen *TButton* von der Seite 'Standard'. Damit haben wir alle Komponenten, die wir für das erste Beispiel benötigen. Vergrößern sie das TDBGrid noch etwas, damit genügend Platz für die Anzeige der Daten zur Verfügung steht.
1414
1515Als nächstes müssen wir die Komponenten miteinander verbinden. Am einfachsten geht das im Objektinspektor. Man kann die Zuweisungen aber auch im Quelltext vornehmen. Ändern sie die 'Transaction' Eigenschaft von IBConnection1 auf 'SQLTransaction1'. Damit wird die 'Database' Eigenschaft von SQLTransaction1 automatisch auf 'IBConnection1' eingestellt. Als nächstes setzen sie die 'Database' Eigenschaft von SQLQuery1 auf 'IBConnection1'. Lazarus ergänzt dann automatisch die 'Transaction' Eigenschaft. Die 'Dataset' Eigenschaft von Datasource1 ändern sie auf 'SQLQuery1'. Zum Schluss müssen sie noch die 'Datasource' Eigenschaft von DBGrid1 auf 'Datasource1' ändern.
1616
1717Wie kommen jetzt die Daten aus der Datenbank auf den Bildschirm? Zunächst müssen wir IBConnection1 mitteilen, wo sich die employee.fdb befindet (üblicherweise im .../examples/empbuild/ Unterverzeichnis ihrer Firebird-Installation). Sie haben jetzt wieder die Wahl, ob sie auf den Objektinspektor zurückgreifen wollen, oder das Verzeichnis im Quelltext zuweisen wollen. Wir entscheiden uns hier für den Objektinspektor. Ändern sie die 'DatabaseName' Eigenschaft von IBConnection1 auf den Pfad zur Datei employee.fdb (z.B. C:\Programme\Firebird\Firebird_2_5\examples\empbuild\EMPLOYEE.FDB). Wenn sie sich den Pfad nicht merken können, dann können sie ihn idR. auch aus ihrem Dateimanager mittels 'kopieren und einfügen' eintragen. Bevor der Datenbank-Server Daten herausrückt, wird er die Berechtigung über Benutzername und Passwort abfragen. Eine ernsthafte Datenbank-Anwendung wird daher beim Programmstart den Benutzer danach fragen, um die Daten im geeigneten Moment an den Datenbank-Server weiterzureichen. Wir werden der Einfachheit halber wieder auf den Objektinspektor zurückgreifen. Ändern sie die 'UserName' Eigenschaft auf 'SYSDBA' und 'Password' auf 'masterkey'. Um zu prüfen, ob die bisher vorgenommenen Einstellungen formal korrekt sind, können sie die 'Connected' Eigenschaft auf 'True' setzen. Ist der Pfad nicht richtig oder stimmt der Benutzername oder das Passwort nicht, dann erscheint eine Fehlermeldung. War die Verbindung erfolgreich, dann trennen sie diese jetzt wieder (auf 'False' setzen).
1818
1919Trotz der erfolgreichen Verbindung wurden aber immer noch keine Daten angezeigt. Das erklärt sich dadurch, dass wir dem Datenbank-Server auch noch nicht mitgeteilt haben, was er anzeigen soll. Die Datenbank employee.fdb enthält mehrere Tabellen. Wenn sie im Vorfeld die Struktur einer Datenbank nicht kennen, dann können sie auf Werkzeuge wie [FlameRobin](http://www.flamerobin.org/index.php) zurückgreifen, um sich die Inhalte anzuzeigen. Aber auch Lazarus bietet ein Hilfsmittel - den Datenbank-Desktop. Sie finden ihn im /tools/lazdatadesktop/ Unterverzeichnis von Lazarus. Öffnen sie das Projekt lazdatadesktop.lpi und kompilieren sie es (setzt FPC 2.6.2 voraus) (unser Beispielprojekt haben sie natürlich vorher gesichert).
2020
2121[framed|center|Der Datenbank-Desktop in Aktion](/wiki-images/d/df/Datadesktop.png)
2222
2323Zurück zu unserem Beispiel. Wir wollen alle Daten aus der Tabelle 'CUSTOMER' anzeigen. Der SQL Befehl dazu lautet:
2424
25-`select * from CUSTOMER`
25+```text
26+select * from CUSTOMER
27+```
2628
2729Diesen Befehl müssen wir der 'SQL' Eigenschaft von SQLQuery1 zuweisen. Im Quelltext unseres Programms würde das so aussehen:
2830
29-`SQLQuery1.SQL.Text := 'select * from CUSTOMER';`
31+``` pascal
32+SQLQuery1.SQL.Text := 'select * from CUSTOMER';
33+```
3034
3135Wird der Befehl in Textform angegeben, dann muss er in einfache Anführungszeichen eingeschlossen werden. Man könnte natürlich auch den Inhalt einer anderen Komponente zuweisen.
3236
3337Die Abfrage der Daten soll erfolgen, wenn der Benutzer auf den Button klickt. Mit einem Doppelklick auf Button1 erzeugt Lazarus das Grundgerüst der dafür notwendigen Prozedur. In ihrem Quelltext sollte jetzt folgendes stehen:
3438
3539``` pascal
3640procedure TForm1.Button1Click(Sender: TObject);
3741begin
3842
3943end;
4044```
4145
4246Zwischen *begin* und *end* müssen wir jetzt die Anweisungen eingeben, die zum Anzeigen der Daten erforderlich sind. Die 'SQL' Eigenschaft von SQLQuery1 kann nur geändert werden, wenn SQLQuery1 nicht aktiv ist. Daher schließen wir die Komponente zunächst:
4347
44-`SQLQuery1.Close;`
48+```text
49+SQLQuery1.Close;
50+```
4551
4652Da wir nicht sicher sein können, ob SQLQuery1 noch irgendwelche Daten enthält, rufen wir die 'Clear' Prozedur auf:
4753
48-`SQLQuery1.SQl.Clear;`
54+```text
55+SQLQuery1.SQl.Clear;
56+```
4957
5058Dann weisen wir der 'SQL' Eigenschaft unsere SQL Anweisung zu:
5159
52-`SQLQuery1.SQL.Text := 'select * from CUSTOMER';`
60+``` pascal
61+SQLQuery1.SQL.Text := 'select * from CUSTOMER';
62+```
5363
5464Jetzt müssen wir die Verbindung zur Datenbank herstellen sowie die Transaktion aktivieren und dann die Abfrage öffnen:
5565
56-`IBConnection1.Connected := True;`\
57-`SQLTransaction1.Active := True;`\
58-`SQLQuery1.Open;`
66+``` pascal
67+IBConnection1.Connected := True;
68+SQLTransaction1.Active := True;
69+SQLQuery1.Open;
70+```
5971
6072Die ersten beiden Anweisungen können auch weggelassen werden, da sie von der dritten Anweisung automatisch erledigt werden (dies gilt aber nicht im umgekehrten Fall beim Trennen der Verbindung). Es wird aber empfohlen, die Anweisungen nicht wegzulassen, da es sonst in einigen Fällen bei einem ROLLBACK zu Problemen kommen kann. Wenn sie jetzt ihr Programm kompilieren würden, dann würden die Daten aus der Tabelle 'CUSTOMER' bereits angezeigt werden. Ein ordentliches Programm wird aber spätestens beim Beenden dafür sorgen, dass noch offene Verbindungen zur Datenbank geschlossen werden. Die Nebenwirkungen wären sonst nicht absehbar. Wir verwenden das OnClose Ereignis unseres Formulars (mittels Doppelklick im Objektinspektor erzeugen):
6173
6274``` pascal
6375procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
6476begin
6577
6678end;
6779```
6880
6981Beim Trennen verwenden wir die umgekehrte Reihenfolge wie beim Verbinden:
7082
71-`SQLQuery1.Close;`\
72-`SQLTransaction1.Active := False;`\
73-`IBConnection1.Connected := False;`
83+``` pascal
84+SQLQuery1.Close;
85+SQLTransaction1.Active := False;
86+IBConnection1.Connected := False;
87+```
7488
7589### Zusammenfassung
7690
7791Wir haben bisher gelernt, wie man mit dem SQLdb Package eine Verbindung zu einer Firebird Datenbank herstellt und die Daten einer Tabelle am Bildschirm anzeigt.
7892
7993## Erweiterung von Beispiel 1
8094
8195Wenn sie sich an die bisherigen Schritte gehalten haben, dann sollte ihr Quelltext etwa so aussehen:
8296
8397``` pascal
8498unit Unit1;
8599
86100{$mode objfpc}{$H+}
87101
88102interface
89103
90104uses
91105 Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs,
92106 IBConnection, sqldb, DBGrids, db, StdCtrls;
93107
94108type
95109
96110 { TForm1 }
97111
98112 TForm1 = class(TForm)
99113 Button1: TButton;
100114 Datasource1: TDatasource;
101115 DBGrid1: TDBGrid;
102116 IBConnection1: TIBConnection;
103117 SQLQuery1: TSQLQuery;
104118 SQLTransaction1: TSQLTransaction;
105119 procedure Button1Click(Sender: TObject);
106120 procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
107121 private
108122 { private declarations }
109123 public
110124 { public declarations }
111125 end;
112126
113127var
114128 Form1: TForm1;
115129
116130implementation
117131
118132{ TForm1 }
119133
120134procedure TForm1.Button1Click(Sender: TObject);
121135begin
122136 SQLQuery1.Close;
123137 SQLQuery1.SQL.Clear;
124138 SQLQuery1.SQL.Text:= 'select * from CUSTOMER';
125139 IBConnection1.Connected:= True;
126140 SQLTransaction1.Active:= True;
127141 SQLQuery1.Open;
128142end;
129143
130144procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
131145begin
132146 SQLQuery1.Close;
133147 SQLTransaction1.Active:= False;
134148 IBConnection1.Connected:= False;
135149end;
136150
137151initialization
138152 {$I unit1.lrs}
139153
140154end.
141155```
142156
143157Nun wird man aber in den seltensten Fällen den kompletten Inhalt einer Tabelle benötigen. Nehmen wir an, es sollen nur die Kunden aus den USA angezeigt werden. Dafür müsste die SQL Anweisung wie folgt lauten:
144158
145-`select * from CUSTOMER where COUNTRY = 'USA'`
159+```text
160+select * from CUSTOMER where COUNTRY = 'USA'
161+```
146162
147163Diese Anweisung werden wir aus zwei Gründen nicht für unser Beispielprogramm verwenden: Zum einen gibt es ein Problem bei der Verwendung des einfachen Anführungszeichens. Der Compiler würde das Anführungszeichen vor USA als schließendes Zeichen betrachten (das erste Zeichen steht ja vor select from...) und damit die SQL Anweisung ungültig machen. Der zweite und gewichtigere Grund ist die Tatsache, dass bei der Entwicklung des Programms noch gar nicht bekannt ist, welche Einschränkung der Anzeige später vorgenommen werden soll. Der Benutzer soll in seiner Flexibilität nicht eingeschränkt werden. Dazu ersetzen wir zunächst 'USA' durch einen Platzhalter:
148164
149-`select * from CUSTOMER where COUNTRY = :COUNTRY`
165+```text
166+select * from CUSTOMER where COUNTRY = :COUNTRY
167+```
150168
151169Die Platzhalter sind durch den führenden Doppelpunkt gekennzeichnet. Um dem Benutzer die Eingabe des Filterwertes zu ermöglichen, platzieren sie eine *TEdit* Komponente (Seite 'Standard' in der Komponentenpalette) auf ihrem Formular. Löschen sie den Wert der 'Text' Eigenschaft. Über die 'Params' Eigenschaft von TSQLQuery können wir nun mit dem in TEdit eingegebenem Text unseren Platzhalter ersetzen:
152170
153-`SQLQuery1.Params.ParamByName('COUNTRY').AsString := Edit1.Text;`
171+``` pascal
172+SQLQuery1.Params.ParamByName('COUNTRY').AsString := Edit1.Text;
173+```
154174
155175Der Parameter kann sowohl über seine Position als auch seinen Namen spezifiziert werden. Letzteres dürfte vor allem die Lesbarkeit des Quelltextes verbessern. Insgesamt sollte die Prozedur jetzt so aussehen:
156176
157177``` pascal
158178procedure TForm1.Button1Click(Sender: TObject);
159179begin
160180 SQLQuery1.Close;
161181 SQLQuery1.SQL.Clear;
162182 SQLQuery1.SQL.Text:= 'select * from CUSTOMER where COUNTRY = :COUNTRY';
163183 SQLQuery1.Params.ParamByName('COUNTRY').AsString := Edit1.Text;
164184 IBConnection1.Connected:= True;
165185 SQLTransaction1.Active:= True;
166186 SQLQuery1.Open;
167187end;
168188```
169189
170190Sie können jetzt ruhig mit den Einstellungen ein wenig herumspielen. Wenn sie einen Filterwert eingeben, der in der Datenbank nicht vorhanden ist, dann wird eine leere Tabelle angezeigt. Es können jedoch auch ernsthafte Probleme auftreten. Da bei einer Client-Server-Anwendung üblicherweise Client und Server räumlich getrennt sind, ist meist nicht auf den ersten Blick ersichtlich, warum es zu einem Problem gekommen ist. Ist der Server heruntergefahren worden oder hat nur jemand einen Stecker gezogen? Zugriffe auf eine Datenbank sollten daher **immer** in eine try ... except und/oder try ... finally Schleife eingebunden werden. Nur so ist sichergestellt, dass Datenbankfehler abgefangen werden können und der Anwender nicht im Regen stehen gelassen wird. Für unsere Beispielanwendung könnte eine rudimentäre Behandlungsroutine wie folgt aussehen:
171191
172192``` pascal
173193begin
174194 try
175195 SQLQuery1.Close;
176196 ...
177197 SQLQuery1.Open;
178198 except
179199 on EDatabaseError do
180200 begin
181201 MessageDlg('Fehler','Es ist ein Datenbankfehler aufgetreten.',mtError,[mbOK],0);
182202 Edit1.Text:='';
183203 end;
184204 end;
185205end;
186206```
187207
188208Hier wird jedoch nur eine einfache Meldung ausgegeben.
189209
190210## Siehe auch
191211
192212- [[SQLdb Package]]: Informationen über das SQLdb Package
193213- [[SQLdb Programming Reference]]: eine Übersicht über das Zusammenspiel der Datenbankkomponenten von SQLdb
194214- [[SqlDBHowto/de]]: Informationen zur Verwendung des SQLdb Packages
195215- [LazInfos](http://sourceforge.net/project/showfiles.php?group_id=203326): enthält allgemeine Informationen zu Lazarus sowie über Datenbanken
196216- [[Working With TSQLQuery]]: Informationen über TSQLQuery
197217
198218---
199219*From the Free Pascal wiki, page "Database tutorial SQLdb1/de", as it stood on 2022-01-12 after a change by Crore, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history