vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbacknächstes Kapitel


Tag 20

Datenbankanbind ung

Heute werden wir uns mit dem Thema Datenbanken beschäftigen. Die Arbeit mit Datenbanken ist für professionelle Websites ein Quasi-Muss, und das Ganze ist eigentlich gar nicht so schwer, wenn man nur einmal weiß, wie. Am heutigen Tage weihen wir Sie in die Geheimnisse der Datenbanksteuerung ein.

Die Themen heute:

20.1 Was ist eine Datenbank?

Der Begriff »Datenbank« ist selbstbeschreibend. Unter einer Datenbank versteht man einen Speicher für Daten. Und zwar für eine ganze Menge von Daten. Diese Daten sind in einer bestimmten Struktur angeordnet. Im Folgenden erfahren Sie eine ganze Reihe von Dingen über Datenbanken im Allgemeinen. Zwar hat jede Datenbank ihre Eigenheiten, Spezialitäten sowie individuellen Vor- und Nachteile, aber das meiste, was Sie nun lesen werden, ist von der letztendlich verwendeten Datenbank völlig unabhängig. Aber keine Angst vor der grauen Theorie, in der zweiten Hälfte des heutigen Tages werden wir in die Praxis übergehen und unterschiedliche Datenbanken mit ASP und PHP ansteuern.

Warum wir kein Perl verwenden? Nun, bei ASP und PHP ist die Datenbankunterstützung mehr oder weniger mit eingebaut, bei Perl benötigen Sie externe Module, und deren Ansteuerung ist - je nach verwendeter Datenbank - unterschiedlich. Und da Perl eh bei der Webprogrammierung auf dem absterbenden Ast ist (nicht nur unserer Meinung nach), sollten auch Sie für fortschrittliche Programmierung Ihr Hauptaugenmerk auf ASP und PHP richten.

Die Daten innerhalb einer Datenbank sind in Tabellen angeordnet. Die Tabelle wiederum besteht aus mehreren Zeilen und Spalten. Wenn Sie bereits einmal mit einer Tabellenkalkulation gearbeitet haben (beispielsweise Excel oder Quattro Pro), kennen Sie das Prinzip möglicherweise. Jede Tabellenspalte hat ein bestimmtes Format, enthält beispielsweise einen String, eine Zahl oder ein Datum.

Datenmodellierung

Vor jeder Programmierung steht die Modellierung der Datenbank. Im Folgenden werden wir das einmal exemplarisch vorführen, und dabei auch unterschiedliche Ansätze präsentieren. Wir werden jedoch ganz klar sagen, wo unsere persönlichen Präferenzen liegen.

Aber nun zu einem konkreten Beispiel, und ganz im Zeichen des E-Commerce nehmen wir als Beispiel einen Online-Shop. In diesem Online-Shop werden eine Reihe von Waren verkauft, und die Bestellungen sollen in einer Datenbank abgespeichert werden. Zunächst überlegen wir uns, welche Daten überhaupt in der Datenbank gehalten werden müssen:

Ein erster Ansatz für den Datenbankaufbau könnte ungefähr folgendermaßen aussehen:

Name

Datentyp

Beschreibung

auftragsnummer

String oder Zahl

Auftragsnummer

vorname

String

Vorname des Bestellers

nachname

String

Nachname des Bestellers

strasse

String

Straßenanschrift des Bestellers

plz

String

Postleitzahl des Bestellers

ort

String

Wohnort des Bestellers

artikel

String

Bestellte Artikel, nebst Anzahl

datum

Datum

Datum der Bestellung

Tabelle 20.1: Ein erster Ansatz für unsere E-Commerce-Datenbank

Sie sehen hier gleich eine häufig verwendete Konvention für Spaltennamen: Nur Kleinbuchstaben!

Dieser Ansatz funktioniert tatsächlich - in der Praxis werden Sie ihn jedoch so gut wie nie antreffen. Dieses Datenbankmodell weist nämlich Redundanz auf - das heißt, Informationen werden zu oft gespeichert. Stellen Sie sich vor, ein Kunde bestellt mehrmals im Online-Shop. Dann befinden sich in der Tabelle mehrere Einträge - Zeilen -, die eine Bestellung dieses Kunden beschreiben. In jeder dieser Zeilen steht der Name des Kunden sowie seine Anschrift - und bei jeder Bestellung somit das Gleiche. Und dies nennt man Redundanz.

Relationales Datenbankmodell

Aus diesem Grund verwendet man bei der Datenbankmodellierung heutzutage zumeist ein relationales Datenbankmodell. Anstelle von einer einzigen, großen Tabelle, teilt man die Daten auf mehrere Tabellen auf, die in einer bestimmten Art und Weise miteinander verknüpft sind. In unserem Beispiel lohnt es sich also, eine Tabelle für die Kunden einzurichten. Diese Tabelle habe den Namen kunden:

Name

Datentyp

Beschreibung

kundennummer

String oder Zahl

Kundennummer

vorname

String

Vorname des Kunden

nachname

String

Nachname des Kunden

strasse

String

Straßenanschrift des Kunden

plz

String

Postleitzahl des Kunden

ort

String

Wohnort des Kunden

Tabelle 20.2: Die Tabelle kunden

Wie Sie sehen, hat jeder Kunde eine Kundennummer, die natürlich eindeutig sein muss. In anderen Worten, jeder Kunde hat eine andere Kundennummer. In der Spalte kundennummer steht also ein eindeutiger Bezeichner für den Eintrag in der Tabelle. Dies nennt man auch einen Primärschlüssel.

Die zuvor entwickelte Tabelle kann nun wie folgt vereinfacht werden:

Name

Datentyp

Beschreibung

auftragsnummer

String oder Zahl

Auftragsnummer

kundennummer

String oder Zahl

Kundennummer des Bestellers

artikel

String

Bestellte Artikel, nebst Anzahl

datum

Datum

Datum der Bestellung

Tabelle 20.3: Die Tabelle bestellungen

In der Spalte kundennummer steht die Kundennummer des Bestellers. Diese Kundennummer ist der Primärschlüssel in der Tabelle kunden, das heißt also, über die Angabe dieser Nummer kann auf den gesamte Adressdatensatz des Kunden zugegriffen werden. Man sagt in diesem Fall auch, die Spalte kundennummer der Tabelle bestellungen enthält einen Fremdschlüssel. Zusammenfassend: Ein Fremdschlüssel ist ein Primärschlüssel einer anderen Tabelle.

Noch eine weitere neue Begrifflichkeit. Es ist nun so, dass ein Kunde mehrere Bestellungen tätigen kann, jede Bestellung aber genau einem Kunden zugeordnet werden kann. Zwischen den Tabellen kunden und bestellungen gibt es damit eine sogenannte 1:n- Beziehung.

Ein weiteres Problem am bisherigen Datenmodell liegt in der Abspeicherung der einzelnen, bestellten Artikel. Bis jetzt ist das durch ein einziges Feld gelöst, einem String. Ein möglicher Wert ist etwa »ein Buch mit der ISBN 3-8272-5764-6 zum Preis von 49,95 DM, sowie zwei Exemplare des Buchs mit der ISBN 90-430-0128-7«. Das ist natürlich im Sinne einer effizienten Warenwirtschaft völlig untragbar. Außerdem soll ja das Online- Bestellsystem auch aus einer Datenbank gefüttert werden. Es ist also eine gute Idee, die Artikel, die bestellt werden können, auch in der Datenbank zu speichern. Die Idee liegt nahe, dazu eine eigene Tabelle anzulegen. Diese könnte folgendermaßen aussehen:

Name

Datentyp

Beschreibung

bestellnummer

String oder Zahl

Bestellnummer des Artikels

beschreibung

String

textuelle Beschreibung des Artikels

preis

Zahl

Preis des Artikels (in _ oder DM)

Tabelle 20.4: Die Tabelle artikel

Die Frage ist nun, wie das mit der Tabelle bestellungen in Einklang zu bringen ist. Zwar könnte die Spalte bestellnummer (welche der Primärschlüssel der Tabelle artikel ist) als Fremdschlüssel eingebaut werden, aber Sie müssen immer noch festhalten, welcher Artikel wie oft bestellt worden ist. Manche Leute, die gerne Excel einsetzen (oder eine andere Tabellenkalkulation), legen nun beliebig viele Spalten an, und ermöglichen damit beliebig viele zu bestellende Artikel; in einer Datenbank ist das aber nicht mehr so ohne Weiteres möglich, da die Anzahl der Spalten im Vornherein feststehen muss. Zwischen den Tabellen artikel und bestellungen gibt es eine sogenannte n:m-Beziehung, denn ein Artikel kann Teil von mehreren Bestellungen sein, und eine Bestellung kann mehrere Artikel enthalten. In so einem Fall führt man eine weitere Tabelle ein, welche die Verbindung zwischen den Artikeln und den Bestellungen herstellt. Steht in einer Zeile dieser Tabelle die Bestellnummer X und der Artikel Y, dann bedeutet dies, das in der Bestellung X der Artikel Y bestellt worden ist. Um festzustellen, welche Artikel alle in Bestellung X bestellt worden sind, müssen Sie in der neuen Tabelle alle Zeilen heraussuchen, die die Bestellnummer X enthalten.

Einen Punkt haben wir noch vergessen: Es muss noch festgehalten werden, wie oft der jeweilige Artikel bestellt worden ist. Damit ist die Tabelle auch schon fertig. Als Name nimmt man oft die Namen der beiden Tabellen, die in einer n:m-Beziehung zueinander stehen, und trennt diese mit einem Unterstrich:

Name

Datentyp

Beschreibung

artikel_bestellungen_id

Zahl

Primärschlüssel

bestellnummer

String oder Zahl

Bestellnummer des bestellten Artikels

auftragsnummer

String oder Zahl

Auftragsnummer

anzahl

Zahl

Anzahl, wie oft der Artikel in der Bestellung enthalten ist

Tabelle 20.5: Die Tabelle artikel_bestellungen

Sie werden bemerkt haben, dass diese Tabelle auch einen Primärschlüssel enthält, obwohl dieser nicht als Fremdschlüssel in einer anderen Tabelle verwendet wird. Es ist jedoch generell eine gute Praxis, jeder Tabelle einen Primärschlüssel zuzuweisen, und sei dies nur eine fortlaufende Nummer des Eintrags.

Somit ist unser Datenmodell fertig. Die Tabelle bestellungen muss nur noch wie folgt angepasst werden - die bestellten Artikel stehen ja jetzt in einer anderen Tabelle:

Name

Datentyp

Beschreibung

auftragsnummer

String oder Zahl

Auftragsnummer

kundennummer

String oder Zahl

Kundennummer des Bestellers

datum

Datum

Datum der Bestellung

Tabelle 20.6: Die Tabelle bestellungen

Beispieldaten

Somit haben Sie in Tabelle 20.2, Tabelle 20.4, Tabelle 20.5 und Tabelle 20.6 ein vollständiges, und auch relativ funktionsfähiges Datenmodell erstellt, das wir auch im Folgenden weiterverwenden werden. Damit Sie sich das Ganze noch einmal direkt am Beispiel verdeutlichen können, hier einige Beispieldaten für die Datenbank. Beginnen wir mit der Tabelle kunden:

kundennummer

vorname

nachname

strasse

plz

ort

123456-abc

Erik

Franz

Martin-Kollar-Str. 10-12

81829

München

08/15

Bill

Gates

One Microsoft Way

12345

Redmond

K-2.4.0

Linus

Torvalds

Freedom Circle

67890

Santa Clara

Tabelle 20.7: Beispieldaten für die Tabelle kunden

Die Tabelle artikel, welche die zu bestellenden Waren nebst Preis enthält (noch in DM), kann folgendermaßen gefüllt sein:

bestellnummer

beschreibung

preis

3-8272-6003-5

Louis/Wenz: Dynamic Web-Publishing in 21 Tagen

89,95

3-8272-5762-X

Louis/Pott: Frontpage 2000 Kompendium

89,95

3-8272-5764-6

Wenz/Hauser: Jetzt lerne ich Dynamic Web-Publishing

49,95

Tabelle 20.8: Beispieldaten für die Tabelle artikel

Als nächstes wird die Tabelle bestellungen gefüllt. Dazu benötigen Sie die Kundennummern aus der Tabelle kunden.

auftragsnummer

kundennummer

datum

1

08/15

01.01.2001

2

K-2.4.0

13.03.2001

3

08/15

19.04.2001

Tabelle 20.9: Beispieldaten für die Tabelle bestellungen

Damit sind die Bestellungen aber noch nicht vollständig erfasst - die Tabelle artikel_bestellungen muss noch mit den Bestelldaten gefüllt werden:

artikel_bestellungen_id

bestellnummer

auftragsnummer

anzahl

1

3-8272-6003-5

1

1

2

3-8272-5764-6

1

1

3

3-8272-5762-X

2

3

4

3-8272-5762-X

3

5

Tabelle 20.10: Beispieldaten für die Tabelle artikel_bestellungen

Sie können nun beispielsweise erkennen, dass Linus Torvalds am 13. März 2001 drei Exemplare des »Frontpage 2000 Kompendiums« bestellt hat. Und diese Daten stehen jetzt nicht mehr in einer Tabelle, sondern sind in vier Tabellen verteilt. Der Lohn sind übersichtlichere, kleinere Tabellen, sowie weniger Redundanz. Aber gehen wir nun direkt in die Praxis über - wie bringen Sie Ihrer Datenbank bei, solche Tabellen anzulegen, und auch noch mit Daten zu füllen oder Informationen daraus auszulesen?

20.2 SQL

In den siebziger Jahren hat IBM, damals ein Pionier in der Datenbankentwicklung, eine standardisierte Abfragesprache entwickelt, um damit die verschiedensten Datenbanken anzusprechen, und zwar unabhängig vom Datenbanktyp oder -hersteller. Die erste Version dieser Sprache hieß SEQUEL, in der Folge hat man sich aber auf das kürzere SQL geeinigt - Structured Query Language. Die alte Form ist zumindest noch im Sprachgebrauch vorhanden, denn viele Leute sprechen »Microsoft SQL Server« aus wie »Microsoft SEQUEL Server«. Das spricht natürlich nicht unbedingt für die Englisch- Fähigkeiten von Microsoft-Anhängern; das Open-Source-Pendant MySQL wird wie erwartet ausgesprochen.

Tabellen erstellen

Nachdem Sie Ihre Datenbankstruktur erstellt haben, müssen Sie zunächst die einzelnen Tabellen erzeugen. Dazu müssen Sie sich die Datentypen der einzelnen Spalten in den Tabellen überlegen. Nun bietet jeder Datenbankhersteller eigene Datentypen an, so dass Sie an den entsprechenden Stellen nachlesen müssen, was Ihre Datenbank unterstützt und was nicht.

Ganz allgemein soll natürlich nicht verschwiegen werden, dass die meisten Datenbanken eine grafische Oberfläche bieten, mit der Sie die einzelnen Felder auch direkt erstellen können.

In Tabelle 20.11 sehen Sie die häufigsten Datentypen, die von praktisch jeder Datenbank unterstützt werden:

Datentyp

Beschreibung

CHAR(n)

String mit genau n Zeichen

DATETIME

Datumswert

DOUBLE

64 Bit langer Fließkommawert

INTEGER

Numerischer Wert (Integer)

VARCHAR(n)

String mit höchstens n Zeichen

Tabelle 20.11: Die häufigsten Datentypen

Der Unterschied zwischen CHAR und VARCHAR ist, dass bei CHAR immer die maximale Anzahl von Zeichen in der Datenbank reserviert wird; bei VARCHAR wird der Platz in Abhängigkeit vom aktuellen Wert in der Spalte belegt, womit dieser Datentyp bei variabel langen Einträgen effizienter ist.

Um nun eine Tabelle zu erstellen, benötigen Sie das Kommando CREATE TABLE. Dazu geben Sie den Namen der Tabelle an, die Namen der Spalten sowie die entsprechenden Datentypen. Die Tabelle artikel könnte also wie folgt erstellt werden:

Listing 20.1: create_artikel.sql

CREATE TABLE artikel(
bestellnummer CHAR(13) PRIMARY KEY,
beschreibung VARCHAR(255),
preis DOUBLE
)

Durch die Angabe von PRIMARY KEY wird angegeben, dass die entsprechende Spalte Primärschlüssel ist.

Die Tabelle kunden wird ähnlich erzeugt:

Listing 20.2: create_kunden.sql

CREATE TABLE kunden(
kundennummer VARCHAR(20) PRIMARY KEY,
vorname VARCHAR(20),
nachname VARCHAR(20),
strasse VARCHAR(30),
plz CHAR(5),
ort VARCHAR(20)
)

In obiger Anweisung finden Sie einige Einschränkungen; beispielsweise sind für die Postleitzahl exakt fünf Zeichen reserviert. Das mag innerhalb von Deutschland noch sinnvoll sein, wenn Sie auch Kunden aus dem Ausland haben sollten Sie etwa VARCHAR(10) verwenden.

Bei der Tabelle bestellungen gibt es zwei Neuerungen. Zunächst hat jeder Eintrag in der Tabelle eine numerische ID, welche als laufender Zähler realisiert ist. Praktisch alle Datenbanken unterstützen das sogenannte Autowert-Konzept und vergeben diese IDs auf Wunsch automatisch.

Zweite Besonderheit ist die Spalte kundennummer, welche Fremdschlüssel aus der Tabelle kunden ist. Dies muss durch die Anweisung CONSTRAINT Name FOREIGN KEY(kundennummer) REFERENCES kunden angezeigt werden.

Listing 20.3: create_bestellungen.sql

CREATE TABLE bestellungen(
auftragsnummer INTEGER AUTO_INCREMENT PRIMARY KEY,
kundennummer VARCHAR(20),
datum DATETIME,
CONSTRAINT bestellungen_fk1
FOREIGN KEY(kundennummer) REFERENCES kunden
)

Durch INTEGER AUTO_INCREMENT wird ein Integer-Autowert gekennzeichnet. Der erste Eintrag in der Tabelle erhält die ID 1, der nächste die ID 2, und so weiter.

Fehlt nur noch die Tabelle artikel_bestellungen:

Listing 20.4: create_artikel_bestellungen.sql

CREATE TABLE artikel_bestellungen(
artikel_bestellungen_id INTEGER AUTO_INCREMENT PRIMARY KEY,
bestellnummer CHAR(13),
auftragsnummer INTEGER,
anzahl INTEGER,
CONSTRAINT artikel_bestellungen_fk1
FOREIGN KEY(bestellnummer) REFERENCES artikel,
CONSTRAINT artikel_bestellungen_fk2
FOREIGN KEY(auftragsnummer) REFERENCES bestellungen
)

Bevor wir uns nun der eigentlich interessanten und vor allem praxisrelevanteren Seite von SQL zuwenden, hier noch einmal unser Hinweis: Nicht jede Datenbank unterstützt den kompletten SQL-Satz, und in den wenigsten Datenbanken müssen Sie die Tabellen von Hand erstellen. Ihnen steht dazu eine grafische Benutzeroberfläche zur Verfügung, mit der Vieles einfacher geht.

In die Datenbank schreiben

Um eine Datenbank überhaupt erst mit Daten zu füllen, benötigen Sie die INSERT- Anweisung. Diese hat die folgende Syntax:

INSERT INTO Tabelle (
Spalte1,
Spalte2,
...
SpalteX
) VALUES (
Wert1,
Wert2,
...
WertX
)

Die Zeilensprünge haben einen rein kosmetischen Effekt und dienen dazu, dass die SQL-Anweisung übersichtlicher wird. Sie können auch alles in eine Zeile schreiben.

Strings müssen hierbei in einfache Anführungszeichen gefasst werden, numerische Werte benötigen keine Apostrophen (aber es funktioniert auch mit Apostrophen, wenngleich das nicht ganz sauber ist).

Um das Ganze einmal an einem realen Beispiel durchzuführen, füllen wir unsere Beispielstabellen mit den exemplarischen Werten von vorher. Beginnen wir mit der Tabelle kunden:

Listing 20.5: insert_kunden.sql

INSERT INTO kunden (
kundennummer, vorname, nachname, strasse, plz, ort
) VALUES (
'123456-abc', 'Erik', 'Franz', 'Martin-Kollar-Str. 10-12', '81829',
'München'
)
INSERT INTO kunden (
kundennummer, vorname, nachname, strasse, plz, ort
) VALUES (
'08/15', 'Bill', 'Gates', 'One Microsoft Way', '12345', 'Redmond'
)
INSERT INTO kunden (
kundennummer, vorname, nachname, strasse, plz, ort
) VALUES (
'K-2.4.0', 'Linus', 'Torvalds', 'Freedom Circle', '67890',
'Santa Clara'
)

Als nächstes möchten wir die Tabelle artikel füllen. Besonderheit hier: Praktisch alle Datenbanken verwenden - auch aufgrund ihrer amerikanischen Herkunft - Dezimalpunkte anstelle von Dezimalkommata.

Listing 20.6: insert_artikel.sql

INSERT INTO artikel (
bestellnummer, beschreibung, preis
) VALUES (
'3-8272-6003-5', 'Louis/Wenz: Dynamic Web-Publishing in 21 Tagen',
89.95
)
INSERT INTO artikel (
bestellnummer, beschreibung, preis
) VALUES (
'3-8272-5762-X', 'Louis/Pott: Frontpage 2000 Kompendium', 89.95
)
INSERT INTO artikel (
bestellnummer, beschreibung, preis
) VALUES (
'3-8272-5764-6',
'Wenz/Hauser: Jetzt lerne ich Dynamic Web-Publishing', 49.95
)

Beim Schreiben in die Tabelle bestellungen gilt es zwei Dinge zu beachten: Zum einen müssen Sie der Spalte auftragsnummer keinen Wert zuweisen, denn dies macht die Datenbank automatisch (da Datentyp AUTO_INCREMENT). Bei kundennummer müssen Sie unbedingt darauf achten, als Wert einen Primärschlüssel aus der Tabelle kunden zu verwenden, denn sonst ist die Fremdschlüsselbedingung verletzt und die Datenbank gibt eine Fehlermeldung aus.

Sie sehen hier, wozu ein Fremdschlüssel gut sein kann: Die Gefahr, dass fehlerhafte Daten in die Datenbank geschrieben werden können, wird verringert; die sogenannte Datenintegrität bleibt somit erhalten.

Listing 20.7: insert_bestellungen.sql

INSERT INTO bestellungen (
kundennummer, datum
) VALUES (
'08/15', '01.01.2001'
)
INSERT INTO bestellungen (
kundennummer, datum
) VALUES (
'K-2.4.0', '13.03.2001'
)
INSERT INTO bestellungen (
kundennummer, datum
) VALUES (
'08/15', '19.04.2001'
)

Datumswerte sind so eine Sache, insbesondere dann, wenn Sie die Datenbank von einem Skript aus ansteuern. Je nach Version und Hersteller der Datenbank sowie Ländereinstellungen des jeweiligen Betriebssystems muss das Datum in einem anderen Format übergeben werden. In Deutschland üblich ist tt.mm.jjjj, aber in Amerika steht der Monat vor dem Tag, also mm.tt.jjjj oder auch jjjj-mm-tt. Sie müssen also ein wenig herumexperimentieren.

Als Letztes muss noch die Tabelle artikel_bestellungen gefüllt werden:

Listing 20.8: insert_artikel_bestellungen.sql

INSERT INTO artikel_bestellungen (
bestellnummer, auftragsnummer, anzahl
) VALUES (
'3-8272-6003-5', 1, 1
)
INSERT INTO artikel_bestellungen (
bestellnummer, auftragsnummer, anzahl
) VALUES (
'3-8272-5764-6', 1, 1
)
INSERT INTO artikel_bestellungen (
bestellnummer, auftragsnummer, anzahl
) VALUES (
'3-8272-6003-5', 1, 1
)
INSERT INTO artikel_bestellungen (
bestellnummer, auftragsnummer, anzahl
) VALUES (
'3-8272-5762-X', 2, 3
)
INSERT INTO artikel_bestellungen (
bestellnummer, auftragsnummer, anzahl
) VALUES (
'3-8272-6003-5', 3, 5
)

Da in der Tabelle artikel_bestellungen als Fremdschlüssel die Primärschlüssel aus der Tabelle bestellungen verwendet werden, müssen Sie beim Schreiben einer neuen Bestellung in die Datenbank zunächst die Tabelle bestellungen füllen, dann artikel_bestellungen.

Sie benötigen also den Autowert, der einer neuen Bestellung zugewiesen wird. Manche Datenbanken bieten hierzu eine eigene Abfrage an, die diesen Autowert zurückliefert. In Abschnitt 20.2.4 zeigen wir Ihnen eine Alternative.

Die Datenbank aktualisieren

Angenommen, Bill Gates will nicht mehr »Bill« genannt werden, sondern »William H.«. Kein Problem, sagt der Datenbankadministrator, ändern wir das einfach in der Datenbank. Das dazugehörige SQL-Kommando lautet UPDATE, und die Syntax ist folgendermaßen:

UPDATE Tabelle SET
Spalte1 = Wert1,
Spalte2 = Wert2,
...
SpalteX = WertX
WHERE Bedingung

Beginnen wir mit einem einfachen Beispiel:

UPDATE kunden SET
vorname = 'William H.'

Diese Anweisung würde das Feld vorname auf den Wert »William H.« setzen - und zwar bei allen Tabelleneinträgen. Das ist natürlich unerwünscht, denn es soll nur der Eintrag von Bill Gates geändert werden. Hierzu dient die WHERE-Bedingung:

UPDATE kunden SET
vorname = 'William H.'
WHERE nachname = 'Gates'

Es lassen sich mehrere Bedingungen mit den booleschen Operatoren AND, OR und NOT miteinander verknüpfen, wie Sie das bereits von VBScript gewohnt sind:

UPDATE kunden SET
vorname = 'William H.'
WHERE nachname = 'Gates' AND ort = 'Redmond'

Bei den Textvergleichen können Sie auch Jokerzeichen verwenden; anstelle des Gleichheitszeichens kommt dann der Operator LIKE zum Einsatz. SQL kennt die beiden folgenden Jokerzeichen:

Innerhalb von Access gibt es andere Jokerzeichen: ? steht für ein beliebiges Zeichen, * für beliebig viele Zeichen. Wenn Sie Access über ODBC ansteuern (dazu weiter unten mehr), müssen Sie jedoch wieder die »originalen« SQL-Jokerzeichen verwenden.

Die beiden folgenden Abfragen haben denselben Effekt, wenn Sie auf den Datenbestand aus Tabelle 20.7 angewandt werden:

UPDATE kunden SET
vorname = 'William H.'
WHERE nachname LIKE 'G_t_s'
UPDATE kunden SET
vorname = 'William H.'
WHERE nachname LIKE 'G%s'

Sie sehen an dieser Stelle übrigens einen weiteren Vorteil eines relationalen Datenbankmodells. Hätten wir nur eine Tabelle, so müssten wir für jede Bestellung von Bill Gates einen Datensatz aktualisieren. In unserem relationalen Modell muss nur genau ein Datensatz geändert werden.

Aus der Datenbank lesen

Das Schreiben in eine Datenbank ist noch relativ einfach, das Herauslesen kann da durchaus komplexere Züge annehmen. Aber wir gehen schrittweise vor, so dass Sie auch dies vor keine unüberwindbaren Hindernisse stellen sollte. Zunächst einmal die (vereinfachte) Syntax der dazugehörigen Anweisung, SELECT:

SELECT Felder FROM Tabelle
WHERE Bedingung

Um also alle Vor- und Nachnamen aus der Kundentabelle auszuwählen, gehen Sie wie folgt vor:

SELECT vorname, nachname FROM kunden

Alle Vor- und Nachnamen derjenigen Personen, die ein r im Nachnamen haben (Erik Frank und Linus Torvalds) erhalten Sie mit diesem Statement:

SELECT vorname, nachname FROM kunden
WHERE nachname LIKE '%r%'

Wenn Sie alle Felder aus einer Tabelle möchten, müssen Sie nicht jeden einzelnen Spaltennamen extra angeben; verwenden Sie den Stern als Jokerzeichen:

SELECT * FROM kunden

Eine weitere Anwendung ist das Zählen der Treffer, die auf so eine Selektion gefunden werden. Hierzu dient COUNT:

SELECT COUNT(nachname) FROM kunden
WHERE nachname LIKE '%r%'

Obige SQL-Anweisung liefert also die Anzahl der Kunden zurück, deren Nachname ein r enthält. Bei unseren Beispielsdaten sind das 2 Stück.

Schon etwas schwieriger wird es, wenn aus mehreren Tabellen gleichzeitig gelesen werden soll. Dies kommt relativ oft vor, denn genau das ist ja der Witz eines relationalen Datenbankmodells. Sie müssen hier hinter FROM die Namen aller beteiligten Tabellen angeben. Vor jedem Spaltennamen sollten Sie den Namen der dazugehörigen Tabelle angeben. Dies ist zwar nur dann ein Muss, wenn ein Spaltennamen mehrfach vorkommt (in verschiedenen Tabellen), aber es dient der Verständlichkeit der Anweisung, wenn Sie so vorgehen.

Zunächst einmal soll festgestellt werden, wie viele Bestellungen Bill Gates bis dato getätigt hat. Folgende SELECT-Anweisung löst dieses Problem:

SELECT COUNT(bestellungen.auftragsnummer) FROM bestellungen, kunden
WHERE kunden.nachname = 'Gates'
AND kunden.kundennummer = bestellungen.kundennummer

Zur Erläuterung: Es werden die Einträge in der Spalte auftragsnummer der Tabelle bestellungen gezählt. Als Bedingung muss gelten, dass der Nachname des Kunden auf »Gates« lautet. Die dazugehörige Kundennummer muss im selben Eintrag in der Tabelle bestellungen stehen. So ist gewährleistet, dass nur diejenigen Datensätze betrachtet werden, die zu Bill Gates gehören.

Je nachdem, welches Datenbanksystem Sie verwenden, wird nach so einer Abfrage ungefähr folgendes Ergebnis erscheinen:

COUNT(bestellungen.auftragsnummer)                    
----------------------------------                   


(1 row(s) affected)

Bill Gates hat also bereits zweimal bei unserem Online-Shop bestellt.

Sie können die SQL-Anweisung wie oben erläutert auch ein wenig kürzer fassen, indem Sie die Tabellennamen vor den Spaltennamen in den Fällen weglassen, in denen der Spaltenname eindeutig ist:

SELECT COUNT(auftragsnummer) FROM bestellungen, kunden
WHERE nachname = 'Gates'
AND kunden.kundennummer = bestellungen.kundennummer

Nun zu einem etwas komplexeren Beispiel: Es sollen die Bestellnummern aller Artikel ausgegeben werden, die Bill Gates bis dato bestellt hat. Der bequeme Weg sieht nun so aus, dass der Datensatz von Bill Gates gesucht wird, die entsprechende Kundennummer in einer Variablen gespeichert wird und dann mithilfe dieser Kundennummer die Tabelle bestellungen durchsucht wird. Anhand der dort gefundenen Auftragsnummern kann dann über artikel_bestellungen auf die Bestellnummern zugegriffen werden. Mit SQL geht das in nur einer Anweisung:

SELECT artikel_bestellungen.bestellnummer 
FROM bestellungen, kunden, artikel_bestellungen
WHERE nachname = 'Gates'
AND kunden.kundennummer = bestellungen.kundennummer
AND bestellungen.auftragsnummer =
artikel_bestellungen.auftragsnummer

Sie sollten eine Ausgabe in diesem Stile erhalten:

bestellnummer        
-------------       
3-8272-6003-5       
3-8272-5764-6       
3-8272-6003-5       
3-8272-6003-5       

(4 row(s) affected)

Wenn Sie nur an unterschiedlichen Bestellnummern interessiert sind, müssen Sie das Schlüsselwort DISTINCT verwenden:

SELECT DISTINCT artikel_bestellungen.bestellnummer 
FROM bestellungen, kunden, artikel_bestellungen
WHERE nachname = 'Gates'
AND kunden.kundennummer = bestellungen.kundennummer
AND bestellungen.auftragsnummer =
artikel_bestellungen.auftragsnummer

Hier die Ausgabe dieser Abfrage:

bestellnummer        
-------------       
3-8272-6003-5       
3-8272-5764-6       

(2 row(s) affected)

Wenn Sie das ganze auch noch lexikalisch sortiert haben möchten, müssen Sie die Anweisung ORDER BY verwenden. Dahinter kommt der Name der zu sortierenden Spalte (oder Spalten), und ASC für aufsteigend (ascending, Standard) bzw. DESC für absteigend (descending).

SELECT DISTINCT artikel_bestellungen.bestellnummer
FROM bestellungen, kunden, artikel_bestellungen
WHERE nachname = 'Gates'
AND kunden.kundennummer = bestellungen.kundennummer
AND bestellungen.auftragsnummer =
artikel_bestellungen.auftragsnummer
ORDER BY artikel_bestellungen.bestellnummer

Die Ausgabe ändert sich wie Folgt:

bestellnummer        
-------------       
3-8272-5764-6       
3-8272-6003-5       

(2 row(s) affected)

Wenn Sie nun nicht die Bestellnummern haben möchten, sondern die Titel der Bücher, müssen Sie die Abfrage noch um die Tabelle artikel erweitern:

SELECT DISTINCT artikel.beschreibung
FROM bestellungen, kunden, artikel_bestellungen, artikel
WHERE nachname = 'Gates'
AND kunden.kundennummer = bestellungen.kundennummer
AND bestellungen.auftragsnummer =
artikel_bestellungen.auftragsnummer
AND artikel_bestellungen.bestellnummer = artikel.bestellnummer
ORDER BY artikel.beschreibung

Es werden die beiden Titel der von Bill Gates georderten Bücher ausgegeben:

beschreibung      
------------     
Louis/Wenz: Dynamic Web-Publishing in 21 Tagen                           
Wenz/Hauser: Jetzt lerne ich Dynamic Web-Publishing                               

(2 row(s) affected)

Wie versprochen, hier noch ein Hinweis, wie das Auslesen eines Autowerts nach dem Einfügen eines Datensatzes programmiertechnisch zumeist gelöst wird. Einige Datenbanken bieten dazu ein eigenes SQL-Statement an, aber eben nicht alle. Man behilft sich hier insoweit, als dass man im Programmiercode eine zufällige Zeichenkette bestimmt (beispielsweise die aktuelle Uhrzeit und ein paar Zufallszeichen). Diese Zeichenkette wird in eine Spalte des neuen Datensatzes eingefügt. Sie können dann gezielt nach dieser Spalte suchen (denn die zufällige Zeichenkette ist eindeutig), und somit den Autowert ermitteln.

Daten löschen

Manche Leute vertreten die Lehrmeinung, dass man aus einer Datenbank nie Daten löschen sollte, sondern immer eine eigene Spalte haben sollte, welche bei einer Löschung mit einem bestimmten Wert beschrieben wird. Wie dem auch sei, schon alleine der Vollständigkeit halber müssen wir auch auf das Löschen von Daten eingehen. Hierzu dient die SQL-Anweisung DELETE:

DELETE FROM Tabelle
WHERE Bedingung

Um also den Kunden Bill Gates vollständig zu löschen, würden Sie folgendes Kommando verwenden:

DELETE FROM kunden
WHERE nachname = 'Gates'

Wie verwenden den Konjunktiv - würden -, denn Sie sollten dieses Kommando an dieser Stelle nicht ausprobieren, da Sie sich sonst Ihre schönen Testdaten korrumpieren würden.

Wenn Sie eine ganze Tabelle löschen möchten, verwenden Sie DROP TABLE:

DROP TABLE kunden

Soweit unsere Schnelleinführung in SQL. SQL bietet mannigfaltige Möglichkeiten, und alleine aus Platzgründen können wir nicht auf alle eingehen. Für die Anwendungen, die Sie am heutigen Tage noch erstellen werden, ist Ihr Wissen jetzt jedoch ausreichend.

Je nach verwendetem Datenbanksystem gibt es eine andere Maske, in die Sie diese Abfragen eingeben können. Wir gehen hier nicht en detail darauf ein, denn es geht uns heute darum, mit Skriptsprachen eine Datenbank anzusteuern. Bitte konsultieren Sie hier die Dokumentation zu Ihrer Datenbank, wenn Sie diese Schritte von Hand durchführen möchten. In Abbildung 20.1 sehen Sie exemplarisch den MySqlManager, der bei MySQL dabei ist.

Abbildung 20.1:  Der MySqlManager von MySQL für Windows

20.3 ODBC

Unter Open Database Connectivity, oder auch kurz ODBC, versteht man den Standard des Datenbankzugriffs unter Windows. Das Prinzip ist genauso einfach wie überzeugend. Es ist egal, ob Sie als Datenbank Access, MySQL, SQL Server, Oracle oder gar Excel einsetzen. Zu jeder Datenbank muss einfach ein ODBC-Treiber installiert sein, der die Hauptarbeit erledigt. Sie, in Ihrer Rolle als Skriptprogrammierer, greifen dann über ODBC auf die Datenbank zu, und schicken SQL-Abfragen an den ODBC-Treiber. Dieser Treiber wandelt dann die SQL-Kommandos in die entsprechenden Abfragebefehle für die jeweilige Datenbank um, und liefert das Ergebnis der Abfrage an Ihr Skript zurück.

Ein klassisches Beispiel: Wie oben bereits erwähnt, verwendet Access als Jokerzeichen * und ?, SQL-Standard ist jedoch % und _. Es wäre nun ungünstig, eine Anwendung auf Access aufzusetzen, dabei * und ? zu verwenden, und dann festzustellen, dass aufgrund der Datenmengen ein Microsoft SQL Server die bessere Lösung wäre. Ohne ODBC müssten Sie nun viele Ihrer Abfragen umschreiben, bei der Verwendung von ODBC müssen Sie nichts ändern.

Beim ODBC-Zugriff taucht häufig der Begriff DSN auf. Das steht für Data Source Name, und ist der Name, über den die Datenbank vom ODBC-Treiber aus angesprochen werden kann. Stellen Sie sich das einfach so vor: Der Treiber ruft die Datenbank über ihren Spitznamen auf. Wenn Sie nun von einer Datenbank auf die andere umsteigen, müssen Sie nur der neuen Datenbank den Spitznamen der alten Datenbank zuweisen, und Ihre Skripte funktionieren weiterhin tadellos.

Einen DSN-Eintrag können Sie über die Systemsteuerung (Start/Einstellungen/ Systemsteuerung) einrichten. Je nach Betriebssystemversion heißt der entsprechende Eintrag »Datenquellen 32-Bit«, »ODBC-Datenquellen (32-Bit)« oder ähnlich. Klicken Sie zunächst doppelt auf das Symbol in der Systemsteuerung, und klicken Sie dann auf das Register System-DSN. Das sieht dann ungefähr so aus wie in Abbildung 20.2.

Abbildung 20.2:  Das Register System-DSN

Wählen Sie nun die Schaltfläche Hinzufügen, und es erscheint eine Liste aller im System zur Verfügung stehenden ODBC-Treiber (siehe Abbildung 20.3).

Abbildung 20.3:  Die ODBC-Treiber, die im System installiert sind

Wählen Sie nun einen der Treiber aus, und klicken Sie auf Fertig stellen. Es erscheint nun eine Eingabemaske, die je nach ODBC-Treiber unterschiedlich ist. Dort können Sie die entsprechende Datenbank auswählen oder sogar erstellen lassen. In Abbildung 20.4 sehen Sie, was beim ODBC-Treiber für MySQL zur Auswahl steht; in Abbildung 20.5 das entsprechende Dialogfenster für Access. Das wichtigste Feld ist auf jeden Fall das für den DSN-Namen; unter diesem Namen (im Beispiel: umfrage) können Sie von Ihren Skripten aus die Datenbank ansprechen.

Abbildung 20.4:  Die Einstellungen von MyODBC, dem ODBC-Treiber für MySQL

Abbildung 20.5:  Die Einstellungen im ODBC-Treiber für Microsoft Access

Nach erfolgreicher Einstellung erscheint der neu eingerichtete DSN-Name in der Auflistung im Register System-DSN, und Sie sind startbereit.

20.4 Datenbanken mit ASP

Im Folgenden führen wir Sie in die Geheimnisse der Datenbankprogrammierung mit ASP ein. Als Beispiel werden wir das Ihnen bereits bekannte Gästebuch verwenden. Wir werden sowohl in die Datenbank schreiben, als auch Daten aus der Datenbank auslesen, oder neudeutsch »eine Auswertung fahren«.

Datenbankzugriff

Unter ASP ist die ActiveX-Komponente ADODB zuständig. Das ist im übrigen die Kurzform für ActiveX Data Objects Database.

Zunächst einmal müssen Sie eine Verbindung zur Datenbank herstellen. Hierzu benötigen Sie ein Objekt vom Typ ADODB.Connection:

<%
Set objConn = Server.CreateObject("ADODB.Connection")
%>

Dann müssen Sie diesem Objekt die notwendigen Parameter übergeben: Zu welcher Datenbank soll die Komponente sich verbinden, und wie lautet gegebenenfalls der Benutzername und das Passwort für den Datenbankzugriff:

<%
Conn.Open "dsn=gaestebuch;database=gaestebuch;uid=christian;pwd=geheim"
%>

Zwei Hinweise: Wenn Sie Ihre Datenbank nicht mit einem Passwort schützen, lassen Sie uid und pwd einfach weg. Und, wenn Sie Access verwenden, benötigen Sie unter Umständen auch keinen Benutzernamen, lassen Sie hier den uid-Abschnitt weg.

Wenn Sie keine DSN einrichten möchten oder können, gibt es bei Access auch noch die Möglichkeit, ohne DSN-Eintrag auszukommen. Dazu müssen Sie den kompletten Pfad der Datenbank angeben:

<%
Conn.Open "DRIVER={Microsoft Access Driver (*.mdb)};" & _
"DBQ=c:\datenbanken\gaestebuch.mdb;"
%>

Sie können nun SQL-Statements an die Datenbankverbindung schicken, indem Sie die Methode Execute aufrufen:

<%
objConn.Execute "INSERT INTO gaestebuch (name, kommentar) " &_
"VALUES ('Christian', 'ganz klasse!') "
%>

Wenn Sie ein SELECT-Statement ausführen und am Rückgabewert interessiert sind, benötigen Sie ein weiteres Objekt, das eine Ergebnisliste darstellt. Der Name des Objekts ist ADODB.RecordSet, Sie müssen das aber nicht explizit mit Server.CreateObject deklarieren, das macht der ASP-Interpreter automatisch für Sie:

<%
Set objRs = objConn.Execute("SELECT * FROM gaestebuch")
%>

Das Recordset-Objekt verhält sich wie ein assoziatives Array: Wie bei beispielsweise PHP können Sie über den Schlüssel (in diesem Fall: den Spaltennamen) auf den dazugehörigen Wert zugreifen:

<%
Response.Write objRs("name")
%>

Alternativ dazu können Sie auch über die Position auf die einzelnen Werte zugreifen: mit objRs(0) erhalten Sie den Wert der ersten Spalte, mit objRs(1) den der zweiten Spalte, und so weiter.

Eine Methode und eine Eigenschaft des Recordset-Objekts verdienen noch besondere Erwähnung: Mit objRs.MoveNext wird der nächste Eintrag in einer Ergebnisliste angesprungen; und objRs.EOF gibt an, ob der letzte Eintrag schon erreicht worden ist oder nicht. Folgender Beispielcode gibt beispielsweise alle Kommentare aus, die sich in der Datenbank gaestebuch befinden:

<%
Set objConn = Server.CreateObject("ADODB.Connection")
objConn.Open "dsn=gaestebuch;database=gaestebuch "
Set objRs = objConn.Execute("SELECT * FROM gaestebuch")
While Not objRs.EOF
Response.Write objRs("kommentar") & "<br />"
objRs.MoveNext
Wend
Set objRs = Nothing
objConn.Close
Set objConn = Nothing
%>

Solange der Interpreter noch nicht am Ende der Ergebnisliste angekommen ist (objRs.EOF wäre dann True), wird der Kommentar im aktuellen Eintrag in der Ergebnisliste ausgegeben und dann der nächste Eintrag angesprungen.

Beachten Sie auch, dass am Ende des Skripts alle Objekte wieder aus dem Speicher gelöscht werden, indem sie auf Nothing gesetzt werden!

Gästebuch

Erinnern Sie sich noch an das Gästebuch von Tag 3? Dort befand sich - mit leichten Änderungen - der folgende HTML-Code:

Listing 20.9: gaestebuch.html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN
http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Gästebuch</title>
</head>
<body bgcolor="white">
<h1>Tragen Sie sich bitte in mein Gästebuch ein:</h1>
<form action="gaestebuch_eintragen.asp" method="post">
<table border="0" cellspacing="0" cellpadding="10">
<colgroup span=2">
<col width="230">
<col width="450">
</colgroup>
<tr>
<td align="right" valign="top" width="230">
Geben Sie bitte Ihren Namen an : </td>
<td><input name="name" size="30" maxlength="50"></td>
</tr>
<tr>
<td align="right" valign="top" width="230">
Möchten Sie Ihre E-Mail hinterlassen : </td>
<td><input name="email" size="30" maxlength="50"></td>
</tr>
<tr>
<td align="right" valign="top" width="230">
Haben Sie auch eine eigene Website : </td>
<td><input name="website" size="30" maxlength="50"></td>
</tr>
<tr>
<td align="right" valign="top" width="230">Ihr Kommentar :</td>
<td><textarea name="kommentar" rows="9" cols="50"></textarea></td>
</tr>
<tr>
<td>&nbsp;</td>
<td><input type="submit" value="In Gästebuch eintragen">
<input type="reset" value="Formular zurücksetzen"></td>
</tr>
</table>
</form>
</body>
</html>

Zur Erinnerung sehen Sie in Abbildung 20.6 noch einmal, wie diese Seite im Browser aussieht.

Abbildung 20.6:  Das Gästebuch  im Browser

Beachten Sie, wie wir das action-Attribut des Formulars auf ein Skript namens gaestebuch_eintragen.asp verwiesen haben. Diese Datei gaestebuch_eintragen.asp muss die Werte aus dem Formular nehmen und in die Datenbank schreiben. Die Datenbank selbst ist sehr einfach eingebaut: Für Name, E-Mail-Adresse, Website und Kommentar wird jeweils ein Textfeld definiert.

Das Kommentarfeld sollte möglichst viele Zeichen haben (je nach Datenbank beispielsweise 255 oder 8000), bei den anderen Feldern reichen jeweils 50 Zeichen. Das Schreiben wird dann wie folgt realisiert:

Listing 20.10: gaestebuch_eintragen.asp

<%
Set objConn = Server.CreateObject("ADODB.Connection")
objConn.Open "dsn=gaestebuch;database=gaestebuch "
strSQL = "INSERT INTO gaestebuch (name, email, web, kommentar) " & _
"VALUES ('" & Request.Form("name") & "', " & _
"'" & Request.Form("email") & "', " & _
"'" & Request.Form("website") & "', " & _
"'" & Request.Form("kommentar") & "')"
objConn.Execute(strSQL)
objConn.Close
Set objConn = Nothing
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN
http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Gästebuch</title>
</head>
<body bgcolor="white">
<h1>Daten wurden ins Gästebuch geschrieben!</h1>
<p><a href="gaestebuch_zeigen.asp">Zum Gästebuch</a></p>
</body>
</html>

Das Skript gaestebuch_zeigen.asp, auf das verwiesen wird, liest wiederum alle Einträge aus dem Gästebuch aus und zeigt sie im Webbrowser an:

Listing 20.11: gaestebuch_zeigen.asp

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN
http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Gästebuch</title>
</head>
<body bgcolor="white">
<h1>Einträge im Gästebuch:</h1>
<%
Set objConn = Server.CreateObject("ADODB.Connection")
objConn.Open "dsn=gaestebuch;database=gaestebuch "
Set objRs = objConn.Execute("SELECT * FROM gaestebuch")
While Not objRs.EOF
Response.Write "<p>Name: " & _
Server.HTMLEncode("" & objRs("kommentar")) & "<br />"
Response.Write "E-Mail: " & _
Server.HTMLEncode("" & objRs("email")) & "<br />"
Response.Write "Website: " & _
Server.HTMLEncode("" & objRs("web")) & "<br />"
Response.Write "Kommentar: " & _
Server.HTMLEncode("" & objRs("kommentar")) & "</p>>"
objRs.MoveNext
Response.Write "<hr />"
Wend
Set objRs = Nothing
objConn.Close
Set objConn = Nothing
%>
</body>
</html>

Wozu dient Server.HTMLEncode("" & objRs("Spaltenname"))? Nun, Server.HTMLEncode wandelt einen String in das entsprechende HTML-Äquivalent um. Dies verhindert, das böswillige Zeitgenossen HTML-Code in den Postings verwenden und somit beispielsweise obszöne Grafiken einfügen können. Wenn aber nun objRs("Spaltenname") leer ist, und Sie darauf Server.HTMLEncode aufrufen, gibt es eine Fehlermeldung. Sie müssen also zunächst durch Konkatenation mit einem Leerstring diesen Nullwert in einen String umwandeln.

Somit haben Sie das nötige Rüstwerkzeug, um mit ASP eigene Datenbanken zu programmieren. Wenn Sie eher ein Fan von PHP sind (oder Sie keine andere Wahl haben, Unix/Linux sei Dank), lesen Sie den folgenden Abschnitt!

20.5 Datenbanken mit PHP

Wenn Sie PHP einsetzen, haben Sie in Bezug auf Datenbanken die Qual der Wahl. Außer den Klassikern MySQL und ODBC unterstützt PHP eine ganze Reihe von weiteren Datenbanken direkt, etwa Microsoft SQL Server oder Oracle. In der Praxis werden Sie aber entweder auf MySQL setzen, oder eine Datenbank verwenden, die Sie mit ODBC ansteuern. Aus diesem Grund beschränken wir uns auch hier auf diese beiden Typen.

Datenbankzugriff

Prinzipiell funktioniert der Zugriff unter PHP ähnlich wie bei ASP. Zunächst müssen Sie eine Verbindung zu einer Datenbank aufbauen, dann ein SQL-Kommando an die Datenbank schicken, und eventuell eine Ergebnisliste auswerten. Der Teufel steckt - wie immer - im Detail.

MySQL

Die Verbindung zum MySQL-Server geschieht mit folgendem Kommando:

<?php
mysql_connect("localhost", "benutzer", "geheim");
?>

Anstelle von localhost müssen Sie den Namen des MySQL-Servers eingeben. Sollte dieser lokal auf derselben Maschine wie der Webserver laufen, genügt localhost.

Als nächstes müssen Sie eine Datenbank auswählen, auf die Sie zugreifen möchten:

<?php
mysql_select_db("gaestebuch");
?>

Um Daten in die Datenbank zu schreiben, reicht es, ein entsprechendes SQL-Statement an die MySQL-Datenbank zu schicken. Das entsprechende Kommando heißt mysql_query.

<?php
$sql = "INSERT INTO gaestebuch (name,email,web,kommentar) VALUES (";
$sql .= "'" . $HTTP_POST_VARS["name"] . "', ";
$sql .= "'" . $HTTP_POST_VARS["email"] . "', ";
$sql .= "'" . $HTTP_POST_VARS["website"] . "', ";
$sql .= "'" . $HTTP_POST_VARS["kommentar"] . "')";
mysql_query($sql);
?>

Am Ende sollten Sie die Verbindung zur Datenbank wieder schließen, um den Ressourcenverbrauch gering zu halten:

<?php
mysql_close();
?>

Wenn Sie Daten aus der Datenbank auslesen möchten, müssen Sie ein paar Zeilen mehr programmieren. Die Funktion mysql_query gibt eine numerische ID zurück, welche als Handle für die Ergebnisliste dient. In anderen Worten: Über diese ID können Sie auf die Ergebnisliste zugreifen. Die Funktion mysql_fetch_array liefert ein assoziatives Array mit allen Werten im aktuellen Eintrag in der Ergebnisliste zurück. Gleichzeitig wird das nächste Element der Ergebnisliste angesprungen, so dass ein erneuter Aufruf von mysql_fetch_array den nächsten Eintrag zurückliefert. Um also alle Kommentare in der Datenbank auszugeben, ist dieser Code hilfreich:

<?php
mysql_connect("localhost", "benutzer", "geheim");
mysql_select_db("gaestebuch");
$id = mysql_query("SELECT * FROM gaestebuch");
while ($eintrag = mysql_fetch_array($id)) {
print($eintrag["kommentar"] . "<br />");
}
mysql_close();
?>

ODBC

Wenn Sie ODBC einsetzen möchten, müssen Sie bei PHP auf jeden Fall eine DSN einrichten, es funktioniert hier also (noch) nicht mit Angabe der Access-Datei. Aber da PHP permanent weiterentwickelt wird, ist es durchaus möglich, dass sich das einmal ändern wird.

Aber nun zur grauen Theorie: Die erste Funktion, die Sie verwenden müssen, ist odbc_connect, welche eine Verbindung zur Datenbank aufbaut. Alle drei Parameter - DSN, Benutzername und Passwort - sind Pflicht. Wenn Sie Ihre Datenbank nicht geschützt haben, können Sie als Benutzernamen und Passwort jeweils einen Leerstring angeben. Die Funktion gibt eine ID zurück, welche Sie später noch benötigen (Sie können also parallel mehrere Verbindungen öffnen, und anhand der IDs können Sie später angeben, welches SQL-Statement an welche Verbindung und damit an welche Datenbank übergeben wird).

<?php
$id = odbc_connect("gaestebuch", "benutzer", "geheim");
?>

Um nun ein SQL-Kommando an die Datenbank zu übergeben, rufen Sie odbc_exec auf. Als Parameter übergeben Sie außer dem numerischen Handle das entsprechende SQL- Statement:

<?php
$sql = "INSERT INTO gaestebuch (name,email,web,kommentar) VALUES (";
$sql .= "'" . $HTTP_POST_VARS["name"] . "', ";
$sql .= "'" . $HTTP_POST_VARS["email"] . "', ";
$sql .= "'" . $HTTP_POST_VARS["website"] . "', ";
$sql .= "'" . $HTTP_POST_VARS["kommentar"] . "')";
odbc_exec($id, $sql);
?>

Am Ende sollten Sie die Verbindung zur Datenbank noch schließen:

<?php
odbc_close($id);
?>

Wenn Sie nun Daten aus der Datenbank auslesen möchten, müssen Sie den Rückgabewert von odbc_exec in einer Variablen zwischenspeichern. Sie ahnen es bereits - auch dieser Rückgabewert ist eine numerische ID, und kann später zur Abfrage der Ergebnisliste verwendet werden. Was bei MySQL noch mit mysql_fetch_array ging, funktioniert bei ODBC mit odbc_fetch_row. Diese Funktion liefert aber nicht ein assoziatives Array mit den Einträgen des aktuellen Ergebnisses zurück, sondern liest das aktuelle Ergebnis in den Speicher. Auf die einzelnen Einträge zugreifen können Sie dann mit odbc_result. Als Parameter übergeben Sie - neben der ID der Abfrage - noch den gewünschten Spaltennamen.

Im folgenden Beispiel werden wieder einmal alle Kommentare in der Datenbank untereinander ausgegeben:

<?php
$id = odbc_connect("gaestebuch", "benutzer", "geheim");
$eintrag = odbc_exec($id, "SELECT * FROM gaestebuch");
while (odbc_fetch_row($eintrag)) {
print($odbc_result($eintrag, "kommentar") . "<br />");
}
odbc_close($id);
?>

Gästebuch

Kommen wir nun zum Gästebuch. Egal, ob Sie MySQL oder ODBC einsetzen, Sie müssen zunächst das action-Attribut im Gästebuch auf eine entsprechende URL anpassen:

Listing 20.12: gaestebuch_php.html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN
http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Gästebuch</title>
</head>
<body bgcolor="white">
<h1>Tragen Sie sich bitte in mein Gästebuch ein:</h1>
<form action="gaestebuch_eintragen.php" method="post">
<table border="0" cellspacing="0" cellpadding="10">
<colgroup span=2">
<col width="230">
<col width="450">
</colgroup>
<tr>
<td align="right" valign="top" width="230">
Geben Sie bitte Ihren Namen an : </td>
<td><input name="name" size="30" maxlength="50"></td>
</tr>
<tr>
<td align="right" valign="top" width="230">
Möchten Sie Ihre E-Mail hinterlassen : </td>
<td><input name="email" size="30" maxlength="50"></td>
</tr>
<tr>
<td align="right" valign="top" width="230">
Haben Sie auch eine eigene Website : </td>
<td><input name="website" size="30" maxlength="50"></td>
</tr>
<tr>
<td align="right" valign="top" width="230">Ihr Kommentar :</td>
<td><textarea name="kommentar" rows="9" cols="50"></textarea></td>
</tr>
<tr>
<td>&nbsp;</td>
<td><input type="submit" value="In Gästebuch eintragen">
<input type="reset" value="Formular zurücksetzen"></td>
</tr>
</table>
</form>
</body>
</html>

Das Schreiben in die Datenbank mit PHP (Skript gaestebuch_eintragen.php) funktioniert nun mit MySQL wie folgt:

Listing 20.13: gaestebuch_eintragen_mysql.php

<?php
mysql_connect("localhost", "benutzer", "geheim");
mysql_select_db("gaestebuch");
$sql = "INSERT INTO gaestebuch (name,email,web,kommentar) VALUES (";
$sql .= "'" . $HTTP_POST_VARS["name"] . "', ";
$sql .= "'" . $HTTP_POST_VARS["email"] . "', ";
$sql .= "'" . $HTTP_POST_VARS["website"] . "', ";
$sql .= "'" . $HTTP_POST_VARS["kommentar"] . "')";
mysql_query($sql);
mysql_close();
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN
http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Gästebuch</title>
</head>
<body bgcolor="white">
<h1>Daten wurden ins Gästebuch geschrieben!</h1>
<p><a href="gaestebuch_zeigen.php">Zum Gästebuch</a></p>
</body>
</html>

Bei Verwendung von ODBC ändert sich kaum etwas, nur die Funktionen heißen anders, und Sie müssen mit dem numerischen Handle der Verbindung arbeiten:

Listing 20.14: gaestebuch_eintragen_odbc.php

<?php
$id = odbc_connect("gaestebuch", "benutzer", "geheim");
$sql = "INSERT INTO gaestebuch (name,email,web,kommentar) VALUES (";
$sql .= "'" . $HTTP_POST_VARS["name"] . "', ";
$sql .= "'" . $HTTP_POST_VARS["email"] . "', ";
$sql .= "'" . $HTTP_POST_VARS["website"] . "', ";
$sql .= "'" . $HTTP_POST_VARS["kommentar"] . "')";
odbc_exec($id, $sql);
odbc_close($id);
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN
http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Gästebuch</title>
</head>
<body bgcolor="white">
<h1>Daten wurden ins Gästebuch geschrieben!</h1>
<p><a href="gaestebuch_zeigen.php">Zum Gästebuch</a></p>
</body>
</html>

Die Datei gaestebuch_zeigen.php, auf die verwiesen wird, liest alle Daten aus der Datenbank aus und gibt sie aus. Aus oben bereits erläuterten Sicherheitsgründen werden auch hier die Einträge zunächst in ein HTML-konformes Format umgewandelt. Diesen Zweck erfüllt die PHP-Funktion htmlspecialchars.

Zunächst der Code für MySQL:

Listing 20.15: gaestebuch_zeigen_mysql.php

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN
http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Gästebuch</title>
</head>
<body bgcolor="white">
<h1>Einträge im Gästebuch:</h1>
<?php
mysql_connect("localhost", "benutzer", "geheim");
mysql_select_db("gaestebuch");
$id = mysql_query("SELECT * FROM gaestebuch");
while ($eintrag = mysql_fetch_array($id)) {
print("<p>Name: ");
print(htmlspecialchars($eintrag["name"]) . "<br />");
print("E-Mail: ");
print(htmlspecialchars($eintrag["email"]) . "<br />");
print("Website: ");
print(htmlspecialchars($eintrag["web"]) . "<br />");
print("Kommentar: ");
print(htmlspecialchars($eintrag["kommentar"]) . "</p>");
}
mysql_close();
?>
</body>
</html>

Und zu guter Letzt die Adaption für ODBC:

Listing 20.16: gaestebuch_zeigen_odbc.php

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN
http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Gästebuch</title>
</head>
<body bgcolor="white">
<h1>Einträge im Gästebuch:</h1>
<?php
$id = odbc_connect("gaestebuch", "benutzer", "geheim");
$eintrag = odbc_exec($id, "SELECT * FROM gaestebuch");
while (odbc_fetch_row($eintrag)) {
print("<p>Name: ");
print(htmlspecialchars($odbc_result($eintrag, " name"));
print("<br />");
print("E-Mail: ");
print(htmlspecialchars($odbc_result($eintrag, "email"));
print("<br />");
print("Website: ");
print(htmlspecialchars($odbc_result($eintrag, "web"));
print("<br />");
print("Kommentar: ");
print(htmlspecialchars($odbc_result($eintrag, "kommentar"));
print("</p>");
}
odbc_close($id);
?>
</body>
</html>

In Abbildung 20.7 sehen Sie eine mögliche Ausgabe des Skripts gaestebuch_zeigen.php im Browser.

Abbildung 20.7:  Exemplarische Einträge im Gästebuch

20.6 Fragen und Antworten

Frage:
Wie kann ich feststellen, wie viele Einträge in der Ergebnisliste stehen?

Antwort:
Verwenden Sie eine while-Schleife, durchschreiten Sie die Eingabeliste und zählen Sie dabei in einer Variablen mit. Wenn Sie ASP verwenden, können Sie auch Set objRs = objConn.Execute("SELECT COUNT(*) FROM tabelle") ausführen; die Anzahl steht dann in objRs(0).

Frage:
Wenn ich Strings, die einen Apostrophen enthalten, in die Datenbank einfügen will, erhalte ich eine Fehlermeldung. Was kann ich tun?

Antwort:
Ersetzen Sie Apostrophen (') durch doppelte Apostrophen (''). In ASP verwenden Sie dazu strX = Replace(strX, "'", "''") , in PHP str_replace("'", "''", $x).

20.7 Workshop

Der Workshop enthält Quizfragen, die Ihnen helfen sollen, Ihr Wissen zu festigen, und Übungen, die Sie anregen sollen, das eben Gelernte umzusetzen und eigene Erfahrungen zu sammeln. Versuchen Sie, das Quiz und die Übungen zu beantworten und zu verstehen, bevor Sie zur Lektion des nächsten Tages übergehen.

Quiz

  1. Nennen Sie fünf SQL-Statements!
  2. Was ist ein Autowert?
  3. Nennen Sie zwei Möglichkeiten, eine Tabelle anzulegen!
  4. Wozu benötigen Sie einen DSN-Eintrag?

Übungen

  1. Die Gästebucheinträge sollen nach dem Datum der Erstellung ausgegeben werden, der aktuellste Eintrag zuerst. Überlegen Sie sich zwei verschiedene Ansätze, dieses Problem zu lösen, und setzen Sie einen davon in die Praxis um.



vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbackKapitelanfangnächstes Kapitel


© Markt+Technik Verlag, ein Imprint der Pearson Education Deutschland GmbH