Eine Datenbankabfrage kann als Ergebnis eine Textantwort, meist in Tabellenform liefern. Aber auch grafische Ausgaben beispielsweise als Chart sind denkbar. Als erstes Projekt soll hier eine Suchanfrage an eine Telefonverzeichnis programmiert werden. Die DLL "DbfQuery" wird mittels des Experten als Content-Typ "text/html" generiert. Innerhalb der Prozedur IsapiAction realisieren Sie im Einzelnen folgende Details:
Zuerst separieren Sie die Anfrageparameter. Die Servererweiterung soll sowohl die Abfragemethode "POST" aus einem Suchformular heraus akzeptieren als auch mit Anfragen vom Typ "GET" aus der Adreßzeile des Browsers zurechtkommen.
if AnsiUpperCase(StrPas(ECBMethod))='POST' then begin Liste:=TStringList.Create; GetContentData(Liste); sQuery:=Liste.Values['Name']; Liste.Free; end else sQuery:=ECBQueryString; // bei GET |
Danach erzeugen Sie den Kopf der Antwortseite. Er soll noch unabhängig vom Ergebnis der Suchanfrage sein. Zur Vereinfachung bedienen Sie sich der schon in den vorangegangenen Projekten beschrieben Hilfsroutinen aus der Sammlung "IsapiHlp.PAS". Damit erzeugen Sie hier bequem den gesamten Seitenvorspann unter Angabe von Seitentitel, Hintergrundfarbe und eventuell Hintergrundbild.
s:=HtmlHeader('Abfrage Telefonverzeichnis','FFFFCC','') +'<H1>Abfrageergebnis</H1>' +'Sie haben nach <B>'+ sQuery +'</B> gesucht.'; |
Eine alternative Variante ist es, das prinzipielle Aussehen der Antwortseite in einer externen Vorlagendatei bereitzustellen. Diese müßte Ihr Programm an dieser Stelle laden und die variablen Suchergebnisse in den Mustertext hineinschreiben. Ein solches Vorgehen hat den Vorteil, daß die Ergebnisseite in gewissen Grenzen verändert werden kann, ohne die DLL neu kompilieren zu müssen. Andererseits stellt der Zugriff auf die separate Vorlagendatei eine zusätzliche Belastung und mögliche Fehlerquelle für das Serverscript dar.
Dann beginnt im Kern die Datenbankarbeit. In diesem simplen Beispiel soll per BDE auf eine auf dem Server verfügbare dBASE-Tabelle zugegriffen werden. In eigenen Projekten können Sie selbstverständlich mit Ihrer gewohnten Datenbankumgebung z.B. Interbase-Server oder MS-SQL-Server arbeiten.Da hierbei Laufzeitfehler nie ganz auszuschließen sind, empfiehlt es sich, die ganze Konstruktion in einen try-finally-Block einzubetten. Als erste Aktion wird eine neue und eindeutig identifizierte Datenbanksitzung eröffnet. Das ist innerhalb von ISAPI-DLLs deshalb wichtig, weil ein anderer Client zur gleichen Zeit in einem parallelen Thread innerhalb der selben Datenbank suchen kann. Im Beispiel wird die Thread-ID zur Bildung eines unverwechselbaren Sitzungsnamen herangezogen.
try Ses:=Sessions.OpenSession('Xyz'+IntToStr(Abs(GetCurrentThreadID))); : finally |
Beim Formulieren des SQL-Ausdruckes entscheiden Sie über die Qualität der Suche. Im vorliegenden Fall wird eine einzelne Datentabelle nach Teilausdrücken des Datenfeldes "Name" durchsucht. Sie können hier aber auch viel leistungsfähigere Abfragen entwerfen, die sich über mehrere in Relation stehende Datentabellen erstrecken. All diese Aktionen verlaufen innerhalb des oben beschriebenen Schutzblockes.
Q:=TQuery.Create(nil); Q.DatabaseName:='WebFirma'; Q.SessionName:=Ses.SessionName; Q.SQL.Add('SELECT * FROM "TelefDat.dbf"'); Q.SQL.Add('WHERE Name LIKE "%' + sQuery + '%"'); Q.SQL.Add('ORDER BY Name,Vorname'); Q.Prepare; |
Beim Öffnen der Abfrage sollte Ihnen nun eine auszugebende Datenmenge zur Verfügung gestellt werden. Falls wider Erwarten Fehler beim Öffnen der Query entstehen, wird hier eine Fehlermeldung an den Browser gesandt. Das können Sie auch unterlassen, auf alle Fälle muß der mögliche Datenfehler von Ihrem Programm abgefangen werden.
try Q.Open : except s:=s + '<BR>Fehler beim Öffnen der Abfrage!' end; |
Die Tabelle mit den gefundenen Daten erstellen Sie durch Ausgabe der entsprechenden HTML-Tags. Die einzelnen Datenzeilen und Zellenwerte lassen sich dabei unproblematisch über zwei ineinander verschachtelte Schleifen beschreiben.
s:=s + '<TABLE BORDER=1 WIDTH=100%>' +'<TR><TH>Name</TH><TH>Vorname</TH><TH>Telefon</TH><TH>FAX</TH></TR>'; while not Q.EOF do begin // je Datensatz s:=s + '<TR>'; for i:=0 to 3 do begin // 4 Spalten sData:=Q.Fields[i].AsString; if Length(sData)=0 then sData:=' '; s:=s + '<TD>' + sData + '</TD>'; end; s:=s + '</TR>'; Q.Next; end; s:=s + '</TABLE>'; |
Aber auch Anfragen über die Adreßzeile des Browsers beantwortet die Serverextension korrekt. Die Syntax des Aufrufes lautet:
http://myhost/scripts/DbfQuery.dll?Name |
Unter der Voraussetzung, daß Sie die Felder des Eingabeformulars identisch zu den Feldern der Datenbank benannt haben, kann Ihnen eine Zählschleife über alle Felder der Datenbank die Handarbeit zum Eintragen aller Werte in den neuen Datensatz abnehmen.
T.Open; T.Append; Liste:=TStringList.Create; GetContentData(Liste); for i:=0 to T.FieldCount-1 do begin sFldName:=T.Fields[i].FieldName; sValue:=Liste.Values[sFldName]; T.Fields[i].AsString:=sValue; end; Liste.Free; T.Post; |
Das Beispiel "DbfChart" soll ein Umsatzdiagramm zeichnen, dessen Datenbasis aus der Tabelle "Umsatz.DBF" gewonnen wird. Darin seien zugeordnet zu Verkäufer-Nummern die Umsatzzahlen einzelner Monate und Jahre gespeichert. Als Abrufmethode der DLL wird "GET" geplant, um das Ergebnis später besser in HTML-Dateien einbetten zu können. Ein erster Aufrufparameter sei die vierstellige Verkäufer-Nr, als zweiter durch ein "+"-Zeichen separierte Parameter folgt die vierstellige Jahreszahl.
Zuerst muß einmal die Höhe des maximalen Monatswertes ermittelt werden, um eine Maßstabsfaktor für das Zeichnen des Diagramms zu errechnen. Sonst laufen Sie Gefahr, daß die besten Verkaufsgewinne einfach oben abgeschnitten werden. Auch hier ist eine SQL-Konstuktion hilfreich. Aus dem ermittelten Umsatzmaximum wird anschließend per Division durch die Bildhöhe unter Abzug von beispielsweise 20 Randpixeln der korrekte Streckungsfaktor gewonnen.
Q.SQL.Add('SELECT MAX(Umsatz) FROM "Umsatz.dbf"'); Q.SQL.Add('WHERE VK_Nr="' + sNr + '" AND Jahr=' + sYear); Q.Open; nMax:= Q.Fields[0].AsCurrency; nFak:=(MyBmp.Height-20)/nMax |
Unter diesen Voraussetzungen ist die Datenbankabfrage im engeren Sinne nicht schwer zu formulieren.
Q.SQL.Clear; Q.SQL.Add('SELECT * FROM "Umsatz.dbf"'); Q.SQL.Add('WHERE VK_Nr="' + sNr + '" AND Jahr=' + sYear); Q.Prepare; Q.Open; while not(Q.EOF) do begin x:=Q.FieldByName('Umsatz').AsCurrency; : end; |
Bei der Planung aller Zeichenarbeiten am Bitmap steht es Ihnen frei, ob sie von vornherein mit monochromen oder farbigen Bildern arbeiten. Beschriftungen im Diagramm werden über Aufrufe von
MyBmp.Canvas.TextOut |
Dieses abschließende Projekt finden Sie unter dem Namen "DbfChart" im Quelltext. Bei Tests mit diesem Programm fragen Sie bitte nach der Verkäufer-Nr 4711 oder 1234 und dem Geschäftsjahr 1999. Die Abbildung zeigt Ihnen, wie unter Einsatz einer weiteren ISAPI-DLL eine dynamische Abfrage entsteht, in die die soeben beschriebene Chart-Generierung eingebettet ist.
Nach oben sind also für Ihre eigene Vorhaben alle Grenzen offen. Gutes Gelingen!
J. Hummel, 2000