Session D-DATA

Die Datenbank von
Visual FoxPro 3.0

Peter Herzog
Peter Herzog System & Organisation


EINLEITUNG

Kernstück eines Datenbanksystems ist wie der Name bereits verrät, die Datenbank. Neu für xBase'ler, ein alter Hut für Downsizer. Unterschiede zum großen Bruder MS-SQL. Alles was unter dem Logo "Alles Neue" mit der Datenbank zu tun hat. Stored Procedures zum mit nach Hause nehmen. Trigger wie, wo, warum. Wie man mit Validierungen umgeht. Das richtige Anwenden von Views - sowohl remote als auch lokal. Rushmore - nach wie vor ein wichtiges Thema. Anbindung an einen MS-SQL-Server und was zu beachten ist.

EINFÜHRUNG

Als erstes wollen wir mit einem alten Erbe, aus der frühen Zeit von FoxPro oder besser der xBase-Zeit, aufräumen.

Das was wir bis heute DBF-Datei nannten ist keineswegs ein Database-File sondern eine einfache und schlichte Tabelle.

Warum ich es dabei so genau nehme ? Na ja, grundsätzlich kann man bei einfachen DBF-Files eben nicht von einer Datenbank sprechen, da dort wesentlich mehr vorhanden sein muß, als nur in Zeilen und Spalten gedrängte Daten. Wenn man es genau nimmt, dann ist eine DBF nichts anderes als ein Excel-Spreadsheet, denn die ist auch in Zeilen und Spalten unterteilt.

Bei einer Tabelle nennt man dies nun Felder und Datensätze, aber unter dem Strich ist es nur eine einfache Listendarstellung. Bereits der alte BROWSE-Befehl hat beim Aufruf genau dieses angezeigt.

DBF nicht gleich Datenbank

Kommen wir zurück zur Datenbank. Was zeichnet eine Datenbank nach dem heutigen Verständnis aus.

Also da wären unsere normalen Tabellen. Dann natürlich unsere Indizes. Bis zu diesem Punkt kann bereits FoxPro 2.x folgen. Nun kommen jedoch besondere Bestandteile dazu, die eine echte Datenbank ausmachen.

Stored Procedures oder auch „gespeicherte Prozeduren". Damit ist Programmcode gemeint, der Daten in spezieller Form manipulieren kann. Weiters gibt es da die Trigger, Rules und Defaults. Außerdem sollten spezielle Datentypen vorhanden sein, die das Speichern von Daten etwas transparenter machen. Nicht zu vergessen, die Referentielle Integrität und die Nullwerte.

Auf alles obige mußten wir bisher verzichten, bzw. wußten bisher gar nicht, daß so etwas eventuell wichtig sein konnte. Von manchen Leuten wird gemunkelt, daß sie die Wörter nicht einmal kannten, bzw. aussprechen konnten. Aber um ehrlich zu sein. Bevor ich mit einer echten Datenbank zu tun hatte (und das ist nicht besonders lange her) konnte ich mit den Ausdrücken genauso wenig anfangen.

Also gehen wir mal Schritt für Schritt durch die Materie.

Stored Procedures

damit ist Programmcode gemeint, der Daten in ganz bestimmter Form verändern kann. In der Welt der Großrechner und SQL-Datenbanken wird dies durch die sogenannte SQL-Sprache erledigt. Eigentlich sollte die SQL-Sprache eine Abfragesprache sein, die es auch der Oma von nebenan ermöglicht Ihre Kuchenrezepte aus dem Datenhaufen herauszubekommen. Wer sich jedoch schon einmal über die Sprache darübergewagt hat, der wird bald erkennen, daß die „Oma" wohl eher das Kochbuch zur Hand nehmen wird, als sich aus einer Datenbank Informationen zu holen.

Ich persönlich bin froh, daß SQL ein etwas schwieriger Teil der EDV ist, ansonsten wäre ich ja arbeitslos.

Vom Standpunkt eines Programmierers aus, schreibt man seine Programme lokal auf seinem Rechner und greift mit bestimmten Befehlen auf die Festplatte oder das Netzlaufwerk zu. Die Stored Procedures hingegen laufen sozusagen in der Datenbank ab und belasten somit nicht das eigene Programm.

Dies hat besondere Vorteile. Als erstes ist das Schlagwort „Reuseable Code" anzuführen. Wenn ich Programmcode zentral ablege, dann brauche ich ihn nur einmal schreiben und er steht jedem meiner Programme zur Verfügung. Außerdem muß ich dafür sorgen, daß der Code für alle Problemfälle gewappnet ist, daß heißt, daß man „ordentlich" programmieren muß und sich keine Quick and Dirty´s leisten kann.

Trigger

Die sinngemäße Übersetzung für Trigger wäre der Abzugshebel einer Pistole. Genauso verhalten sich auch die Trigger, hinter denen eine Stored Procedure stecken kann. Es bedeutet schlicht und einfach, daß ein Ereignis eintritt und die Datenbank daraufhin einen Trigger „abfeuert" der wiederum mit einer Aktion auf das Ereignis reagiert. War das nicht ein toller Satz ?

Für den Laien erklärt bedeutet dieses, daß es drei verschiedene Ereignisse in der Datenbank gibt, die man abfangen kann. Datensatz Einfügen, Ändern und Löschen. Es wird alles auf diese drei Ereignisse zurückzuführen sein. Wenn nun eins dieser Ereignisse eintritt, dann kann die Datenbank automatisch weitere Aktionen starten. Als Beispiel wären da Löschoperationen oder ähnliches.

Rules

In jeder Datenbank kann man ein Regelwerk definieren, welches darauf achtet, daß keinerlei „Mülldaten" in die Tabellen gelangen.

Wenn Sie definieren, daß ein bestimmtes Feld in einer Tabelle nicht leer sein darf, dann wird sich die Datenbank mit Händen und Füßen wehren, daß Sie einen solchen Datensatz eingeben, oder darauf ändern.

Also das alte Verhalten des „Ich lege mal schnell 5 leere Datensätze an und schreibe die Daten später hinein" können sie sich sofort aus dem Kopf schlagen. Wenn Sie eine Regel definiert haben, so müssen Sie die Regel zuerst löschen, wenn Sie diese brechen wollen. Und mal ehrlich, wer möchte sich vom Computer schon sagen lassen, was man tun darf und was nicht. Aber dazu später.

Defaults

Wenn Sie zufällig in Deutschland wohnen und einen Kundendatensatz eingeben, dann ist es wohl sinnvoll, wenn das Länderkennzeichen mit einem „D" vorbelegt ist. Wollten Sie dies bisher erreichen, so mußten Sie dieses in jedem Programm hineinprogrammieren, welches Datensätze in der Kundendatei anlegt.

Defaults füllen die Felder bereits mit von Ihnen vorbestimmten Werten, wenn ein Datensatz neu angelegt wird und Sie diese Daten nicht explizit vorgeben.

Spezielle Datenfelder

Über die Datenfelder Zeichen, Numerisch, Datum, Logisch und Memo gibt es durchaus noch andere Möglichkeiten Informationen in Felder zu packen. Als Beispiel wäre das Datum-Zeitfeld, Integer, Double und Währung anzuführen. Es gibt bei bestimmten Datenbanken noch andere, jedoch sind dies meistens nur Abwandlungen der normalen Datentypen.

Spezielle Formen sind z.B. Das Timestamp-field und die user-defined-Datatypes, auf die wir in VFP jedoch noch verzichten müssen.

Referentielle Integrität (RI)

ist ein tolles Modewort und jeder verwendet es. Was steckt jedoch dahinter, besonders wenn man die Besonderheiten: deklarativ oder prozedural noch davor stellt.

Zur Erklärung ein kleines Beispiel.

In unserer Applikation gibt es Aufträge. Zu jedem Auftrag gibt es 1 bis n Positionen. Wenn wir nun einen Auftrag löschen, so hat es wenig Sinn die Positionen noch aufzubehalten. Die sind nun sinnlos geworden.

Ein Teil der RI ist nun die Löschweitergabe (Kaskadierende RI). Das bedeutet, daß automatisch alle Datensätze gelöscht werden, die zu diesem Auftrag dazugehörten.

Wenn nun jedoch ein Teil der Positionen bereits geliefert wurden, dann ist dieser Teil noch zu verrechnen und darf auf keinen Fall gelöscht werden. In diesem Falle ist es eine Restriktive RI, also eine Einschränkung. Sollte dieser Fall eintreten, dann darf der gesamte Auftrag noch nicht gelöscht werden. Die RI überwacht dies selbständig und ohne daß wir irgendeinen Finger rühren müssen.

Nun kurz zum Unterschied zur deklarativen und zur prozeduralen RI. Deklarativ bedeutet, daß ich einfach nur „sage", daß die Datenbank darüber wachen soll. Bei der prozeduralen RI werden die Trigger eingesetzt mittels Stored Procedures darüber zu wachen.

VFP 3.0 hat prozedurale RI, jedoch kann uns das egal sein, da der dazugehörige Code sowieso automatisch erstellt wird.

Nullwerte

Allgemein bekannt ist die Tatsache, daß ein logisches Feld die Zustände „Wahr" und „Falsch" annehmen kann. Mit diesem alten Glauben räumt die Datenbank nun auf und übergibt uns im Falle des logischen Feldes ein eindeutiges „Vielleicht". Sie werden nun sagen, was das nun soll. Etwa ein dritter Zustand ? Schwanger, nicht schwanger, ein bißchen Schwanger ? Nein der dritte Zustand ist eindeutig ein „Vielleicht Schwanger"

Genaugenommen gibt es diesen Zustand wirklich, selbst im richtigen Leben, wenn man es genau nimmt.

Diesen Zustand kann man nun auf alle Datentypen anwenden. Bei Numerisch ist die nun weder 0 noch nicht 0, sondern wie man es in VFP schreibt .NULL.

Auch ein Datum kann einen Nullwert annehmen. Also weder {}, noch {..} oder {00.00.00}. Einfach .NULL.

Interessant wird es bei Zeichenketten. Denn selbst eine leere Zeichenkette unterscheidet sich von einem .NULL. Also genaugenommen ist dies ein neuer Wert, mit dem wir sogar arbeiten können, als ob es eine Zahl oder ein sonstiger Wert wäre.

Doch nun zu VFP 3.0. Wie wirken sich die neuen Begriffe in VFP aus, bzw. wie wurden sie verwirklicht. Als VFP gestylt wurde haben sich die Entwickler natürlich Gedanken über den zukünftigen Aufbau der FoxPro Daten gemacht.

Auf der einen Seite mußte man einen Aufbewahrungsort für die neuen Bestandteile einer Datenbank finden, auf der anderen Seite hatte man ein tolles, sehr schnelles Datenzugriffsmodell.

Es konnten natürlich die gesamten Zugriffstechniken von FoxPro nicht einfach weggeworfen werden, auf der anderen Seite fehlte ein Platz, in dem man die zusätzlichen Informationen speichern konnte, die für eine Datenbank fehlten.

Man ging einen Kompromiß ein. Zuallererst wurde das Aussehen einer Tabelle nur geringfügig geändert, auf der anderen Seite wurde ein sogenannter Datenbankcontainer geschaffen, der alle Teile beinhaltet, die man nicht ein eine Tabelle speichern konnte.

Der Datenbankcontainer DBC

Wollen wir uns einmal selbst einen Datenbankcontainer anschaffen. Der Befehl dazu lautet CREATE DATABASE <Name> oder einfach MODIFY DATABASE <Name>. Sollte beim MODIFY die Datenbank nicht vorhanden sein, so wird sie eben sofort angelegt. Also frisch drauf los und MODI DATO TEST eingetippt.

Auf der Festplatte werden Sie nun drei neue Dateien finden.

TEST.DBC die Datenbank
TEST.DCX der Index
TEST.DCT die Memodatei

Das bereits verrät uns, daß es sich nach guter alter FoxPro Manier wiederum um eine normale Tabelle handelt, die man wie gewohnt auch mit USE aufmachen kann.

Aber an dieser Stelle eine energische Warnung: Händische Änderungen im DBC können der Gesundheit Ihres Datenbankcontainers schaden, so daß Sie mit absolutem Datenverlust rechnen müssen.

Sobald wir einen Datenbankcontainer erzeugt haben, so erhalten wir ein leeres Fenster mit der Überschrift „Datenbankdesigner TEST". Außerdem erhalten wir in der Standardtoolbar den Namen Test in einer Combobox dargestellt.

Sie können beliebig viele Datenbanken gleichzeitig öffnen und dazwischen hin und her schalten. Programmatisch geschieht dies durch des Befehl SET DATABASE TO <Name>. Achten Sie darauf, daß sie den selben Datenbankcontainer mehrmals öffnen können. Mit dem Befehl CLOSE DATA ALL können Sie alle geöffneten auch wieder schließen.

Nun können wir z.B. mit der rechten Maustaste ein Menü aufblättern, in dem wir alle Teile des DBC´s eintragen können.

Als erstes wollen wir einmal eine neue Tabelle anlegen. Nachdem wir einen Namen für die Tabelle vergeben haben erscheint uns der Tabellendesigner, in dem wie die Hauptbestandteile einer Tabelle anlegen können. Beachten Sie, daß sich die Tabelle nun nicht im DBC befinden wird, sondern wie in alten Zeiten, als DBF auf der Festplatte gespeichert wird.

Hier sehen wir bereits den Unterschied zu einer SQL-Datenbank oder z.B. ACCESS. Dort wird nämlich alles in einer riesengroßen Datei abgespeichert. Der Vorteil von VFP-Tabellen liegt in der enormen Geschwindigkeit, der Nachteil ist das „Verbraten" von Filehandles, die in VFP leider noch auf 254 beschränkt sind. Dies wird sich jedoch in einer der nächsten Versionen wesentlich verbessern.

Wenn wir eine solche Tabelle anlegen, so wird im DBC der physikalische Aufenthaltsort der Tabelle und in der Tabelle selbst der Ort des DBC´s gespeichert. Dies bedeutet, daß man Tabelle und DBC nicht mehr trennen darf, da sie eine logische Einheit darstellen, die miteinander verheiratet ist. Bigamie ist auch nicht erlaubt, daß bedeutet, daß eine Tabelle nur ein einem Datenbankcontainer enthalten sein kann.

Will man explizit die Tabelle aus dem DBC entfernen, so muß der Befehl FREE TABLE angewendet werden.

Doch zurück zum Tabellendesigner.

Als erstes muß ich vor dem Dateinamen warnen. Wenn Sie unter Windows 95 oder Windows NT arbeiten, so verleitet es, den Namen über die acht Buchstaben hinaus länger zu schreiben. Wird ein solcher DBC und die Tabellen nun unter Windows 3.x angesprochen, so wird der DBC die Tabelle nicht mehr finden, da nun ein 8 Byte langes Synonym verwendet wird. Also Vorsicht und bleiben Sie bei 8 Buchstaben.

Allerdings kann ein (beinahe) beliebig langer Tabellenname als Alias verwendet werden, denn man ganz oben im ersten Feld des Tabellendesigners eintragen kann.

Nun kann frisch fröhlich Feld für Feld eingetragen werden.

Feldnamen mit 128 Zeichen Länge

Die erste Überraschung erlebt man, wenn man den Namen eines Feldes länger schreibt, als die üblichen 10 Stellen. Genau genommen sind nun 128 Stellen erlaubt, aber natürlich nicht besonders sinnvoll. Man sollte aufpassen, wenn Feldnamen verwendet werden, die länger als die üblichen 10 Stellen sind. Wie wir bereits gehört haben, hat sich die DBF-Struktur nicht geändert. Also werden in der DBF weiterhin nur 10 Stellen gespeichert. VFP 3.0 sorgt selbst dafür, daß der Feldname eindeutig bleibt und vercryptet die Feldnamen auf ähnliche Weise wie die Dateinamen unter Windows 95.

Die Warnung deshalb, da man bei einem eventuellem FREE TABLE die langen Feldnamen natürlich verliert und nur noch die abgekürzten Teile vorfindet.

Die neuen Feldtypen

Wenn man zur Combobox der verfügbaren Feldtypen ankommt, erlebt man bereits die erste Überraschung. Neben den alten Typen Zeichen, Numerisch, Logisch, Datum und Memo gibt es nun auch noch Integer, Double, Währung, Datum-Zeit, Zeichen Binär und Memo Binär.

herausragende Eigenschaften dieser Feldtypen ist die Fähigkeit die Daten zu packen und dadurch Speicherplatz zu sparen. Und nebenbei wird auch noch Zeit gespart, da eine Umwandlung in ein Character-Numeric Format wegfällt.

Integer besteht aus nur 4 Byte und kann somit 32 Bit unterbringen.

Von -2147483647 bis 2147483646. Keine Nachkommastellen.

Double ist eine auf 8 Byte gepackte Fließkommazahl.

Von +/-4.94065645841247E-324 bis +/-1.79769313486232E308

Währung wurde aus dem SQL-Server Bereich übernommen, hat ebenfalls 8 Byte in der Datei jedoch ist auf 4 Nachkommastellen begrenzt und gilt

Von 922337203685477.5808 bis 922337203685477.5807

Datum-Zeit ist eine Kombination aus beiden Teilen und wird ebenfalls in 8 Byte gepackt abgespeichert.

Bei den Binären Datentypen handelt es sich um eine Spezialität aus der Codepageumwandlung. Unter FoxPro 2.x wurde grundsätzlich jedes Feld konvertiert, sobald die Tabelle mit einer Codepage versehen war. Ausnahmen konnte man mit früher dem Befehl SET NOCPTRANS TO <Feldliste> festlegen. Um diesen, heute unwichtigen, Befehl abzuschaffen wurden eben Zeichen Binär und Memo Binär eingeführt, bei denen keine Umwandlung der Zeichen zwischen den Codepages vorgenommen wird.

Zwei Einträge gibt es noch zusätzlich. Einerseits das FLOAT, welches jedoch nur noch aus Kompatiblitätsgründen vorhanden ist und dem Numerisch entspricht und das alte immer wieder grau unterlegte Picture, welches nur auf dem MAC eine Bedeutung hat.

Abhängig vom Datentyp kann man nun die Größe des Feldes eingeben und eventuell auch noch die Nachkommastellen.

Memofelder mit minimal einem Byte

Interessant wird es bei Memofeldern, da diese nur noch 4 Byte im Feld benötigen. Auch die alte Memo-Blockgrößen-Verwaltung wurde geändert. Nun kann die Blockgröße auf 0 gesetzt werden, was einem Byte entspricht. Werden also 21 Byte in das Memofeld geschrieben, so werden auch nur 21 Byte verbraucht.

Der Nullwert im Tabellenfeld

Nun kommen wir zu einer Spalte die ein NULL als Überschrift trägt. Wird hier angekreuzt, so kann dieses Feld einen .NULL. Wert enthalten. Sie können diese .NULL. in jedem Feld ankreuzen. Das Verhalten dabei, wurde weiter oben bereits beschrieben. In einem BROWSE-Fenster können Sie diesen Wert auch eingeben, in den Sie die STRG-Taste und die Taste Null drücken. Aber Achtung. Nicht die NULL auf der Nummerntastatur sondern die beim Gleichheitszeichen auf der normalen Tastatur.

Die Feld Eigenschaften

eine der größten Errungenschaften des Datenbankcontainers sind die nachfolgenden Eigenschaften.

Jedes Feld kann mit einer Regel (Validation Rule) ausgestattet werden, die überprüft wird, sobald das Feld geschrieben wird. (bzw.: davor)

Als Regel kann natürlich auch eine Stored Procedure verwendet werden.

Beispiele für Regeln.

not empty(<Feldname>)
<Feldname> < 10000
procedure()

Wenn die Regel fehlschlägt, bzw. ein .F. zurückliefert, so wird automatisch der Validation Text verwendet und eine Fehlermeldung angezeigt. In einer Form wird die Errormethode angesprungen.

Die Default Value wurde weiter oben ebenfalls bereits beschrieben und kann ebenfalls durch eine Funktion gebildet werden, die als Stored Procedure abgespeichert werden kann.

Letztendlich noch ein Kommentarfeld, welches wahrscheinlich wie immer nicht gefüllt wird, da man dazu meist keine Zeit hat.

Indizes, wie wir es uns wünschen

Als nächstes widmen wir uns den Indizen, bei denen sich ebenfalls etwas entscheidendes getan hat.

Einzugeben sind diese auf der zweiten Page des Tabellendesigners. Hier vermißt man allerdings die Funktionalität des alten 2.x Tabellendesigners, der einem durch Doppelklick auf ein Feld einen Index angelegt hat. Hier müssen wir selbst Hand anlegen und die Namen eintippen.

Indextypen haben wir nun vier zur Verfügung. Zuerst einmal die „alten".

Einfach und Eindeutig. Eindeutig hat uns bereits unter FoxPro 2.x etwas vorgetäuscht, was nicht 100%ig zutrifft. Wenn nämlich ein Index als eindeutig gekennzeichnet wird, so wird nur das erste Vorkommen dieses Ausdrucks in den Index aufgenommen. Eintragen konnte man deshalb trotzdem mehrere gleiche Werte.

Neu hinzugekommen sind Primär und Potentiell. Grundsätzlich sind beide Indextypen identisch. Jedoch kann es in der Tabelle nur einen Primären geben, deshalb sind alle anderen dieses Typs eben nur potentielle Anwärter Primar zu werden. Eine etwas lustige Beschreibung aber so ist es am einfachsten zu erklären.

Auf alle Fälle sind diese Indizes echt „Eindeutig" und lassen keine gleichen Einträge zu. Achten Sie darauf, daß dies auch gelöschte Datensätze mit einschließt. Diesen Effekt können Sie allerdings durch eine FOR-Klausel beim Index umgehen, die .NOT.DELETED() lautet. Achten Sie jedoch darauf, daß solch eine FOR-Klausel Rushmore ausschaltet und dieser Index für keinerlei mengenorientierte Abfrage zu gebrauchen ist.

Jetzt natürlich die Frage wozu denn ein Index als Primär zu kennzeichnen ist.

Benötigt wird dieser Indextyp, um erstens einen kleinen Schlüssel zu zeichnen, der diesen Index kennzeichnet und andererseits um bei einer Referentiellen Integrität herauszufinden, wie die Daten miteinander verknüpft werden können.

Tabellen Eigenschaften

Jede Tabelle kann noch zusätzlich mit sogenannten Table-Rules ausgestattet werden. Ein Klick auf Table-Properties läßt wiederum ein Fenster erscheinen, in dem diese eingegeben werden können.

Zusätzlich zu den Feld-Rules die, die einzelnen Felder abprüfen kann auch noch eine globale Satzregel definiert werden, die beim abspeichern des Satzes durchgeführt wird. Das Verhalten ist identisch mit dem der Feldregeln.

Nun noch zu einem entscheidendem neuen Teil, der weiter oben bereits angesprochen wurde.

Die Trigger

Für jeden Datenbankvorgang (INSERT, UPDATE, DELETE) gibt es die Möglichkeit eine Prozedur zu hinterlegen, die ausgeführt wird, sobald eines dieser Ereignisse eintritt. Sollte eine der Prozeduren .F. zurückliefern, so wird das Ereignis einfach nicht zugelassen und eine Fehlermeldung produziert. In einer Form kann diese Fehlermeldung abgefangen werden.

Nun noch zum Schluß daß Kommentarfeld, welches wie meistens unberührt bleiben wird.

Wenn Sie die Tabelle nun abspeichern so erscheint sie als kleine Tabelle im Datenbankcontainer

Ein Klick auf die rechte Maustaste läßt ein kontextsensitives Menü erscheinen, daß einem die Befehle wie FREE TABLE, MODIFY STRUCTURE usw. erspart.

Stored Procedures (Gespeicherte Prozeduren)

Wie bereits beschrieben sind Stored Procedures Programmteile, die Tabellen usw. bearbeiten können. Bei VFP 3.0 ist dies natürlich FoxPro Code, was uns das Leben wesentlich leichter macht.

Eingeben können Sie diese Prozeduren durch MODIFY PROCEDURE im Befehlsfenster oder durch einen rechten Mausklick im Datenbankfenster.

Alle Prozeduren werden hintereinander geschrieben und verhalten sich wie eine normale PRG-Datei.

Sie können hier auch globalen Prozedur-Code hinterlegen, da bei angewählter Datenbank die Funktionen zur Verfügung stehen, wie eine mit SET PROC TO <Datei> zugebundene Prozedurdatei.

Das spezielle an diesem Code ist die Verfügbarkeit innerhalb der Datenbank.

Wenn Sie eine Tabelle öffnen, die in einem Datenbankcontainer verankert ist, so wird automatisch die DBC mitgeöffnet und somit stehen auch die Prozeduren zur Verfügung, da diese direkt im DBC abgespeichert werden.

Ein Schließen eines DBC´s kompiliert automatisch diesen Code. Dies kann jedoch nachträglich mit COMPILE DATABASE nachgeholt werden.

Referentielle Integrität

Ein Schlagwort, welches auch in VFP3.0 nicht mehr fehlen darf. Wenn man in mehreren Tabellen Indizes definiert hat und einer davon ein Primärer ist, so kann man eine Relation zwischen den Tabellen definieren. Dies ist ganz einfach zu bewerkstelligen, indem man den Primären Index auf einen Index einer anderen Tabelle zieht.

Nach diesem „Drag und Drop" wird eine Linie zwischen beiden Tabellen gezogen, die eine Relation darstellt, welche als Vorschlag in einer Form herangezogen wird.

Ein Klick mit der rechten Maustaste ermöglicht das Bearbeiten der Referentiellen Integrität.

Sobald man nun die RI bearbeitet wird automatisch der sogenannte RI-Builder, ein Steuerelementeassistent gestartet.

Pro angelegter Relation wird eine Zeile angezeigt, in der man die Beziehung zueinander festlegen kann.

Anfangs stehen alle Beziehungen auf „Ignorieren". Durch Klick in die jeweilige Zeile kann die Datenbeziehung zueinander beliebig eingeschränkt oder weitergebend, definiert werden.

Sobald man seine Einstellungen definiert hat, wird automatisch Code generiert, der eine prozedurale RI im DBC verankert. Es werden dabei auch automatisch Trigger in den betroffenen Tabellen eingerichtet.

Aufpassen muß man nur, wenn man verschiedene Sprachversionen von VFP untereinander mischt. In einer englischen Version wird folgender Code ziemlich am Anfang generiert.

IF (UPPER(SYS(2011))="RECORD LOCKED" and !deleted()) OR !RLOCK()

In der deutschen Version wird daraus

IF (UPPER(SYS(2011))="DATENSATZ GESPERRT" and !deleted()) OR !RLOCK()

was sich natürlich negativ auf das Verhalten auswirkt. Allerdings können Sie das Problem umgehen, wenn Sie den RI-Code in der richtigen Version, im Datenbankcontainer neu generieren lassen.

Ansichten (Views)

Eine Besonderheit einer Datenbank ist die sogenannte View. Das bedeutet, daß man Tabellen oder nur Teile davon in spezieller Art „ansieht". Eingestellt werden diese Ansichten im View- oder Ansichtendesigner. Zu erreichen ist dieser durch ein CREATE / MODIFY VIEW <Viewname> im Befehlsfenster oder wieder durch die rechte Maustaste im Datenbankdesigner.

Unterm Strich gesehen ist dieser Designer (fast) identisch mit dem Query-Designer, denn wir bereits als RQBE in FoxPro 2.x kennengelernt haben.

Auch hier wird ein SQL-Statement interaktiv erzeugt, welches Daten aus einer oder mehreren Tabellen zusammenführt, einschränkt, sortiert und gruppiert.

Das Besondere daran ist jedoch, daß diese SQL-Befehle keine Einbahnstraßen darstellen, wie es die Cursor des Querydesigners darstellen. Die hier erzeugten Ansichten sind direkt mit den Originaltabellen verknüpft und können direkt Daten ändern wenn man dies erlaubt.

Das „Erlauben" geschieht in der letzten Page des Viewdesigners.

Die wichtigsten Bestandteile bei den „Update Criteria" sind die Hacken bei „Send SQL Updates" und unterhalb des Schlüssel- und Stiftsymbols.

Der Hacken unter dem Schlüssel gibt an, welches der Schlüsselbegriff der Datei ist, um den Datensatz eindeutig wiederzufinden. Ein Hacken unter dem Stift gibt an, daß dieses Feld „Updateable" d.h. beschreibbar ist.

Der Hacken bei „Send SQL Updates" schließlich gibt an, daß Updates an die originalen Tabellen geschickt wird.

Die restlichen Einstellungsmöglichkeiten haben nur bei sogenannten Remote Views reelle Bedeutung.

Sobald diese Einstellungen gemacht wurden und die View unter einem X-beliebigen Namen abgespeichert wurde, so kann man die View, gleich einer Tabelle, mit USE öffnen und es wird sofort ein SQL-Befehl ausgeführt, der einem die Daten in der gewünschten Form darstellt.

Man kann nun wie in einer normalen Tabelle mit SKIP oder GO <Datensatz> arbeiten. Alle Felder, die als Updateable gekennzeichnet wurden werden auch automatisch zurückgeschrieben, wenn man einen Wert ändert.

REMOTE VIEWS

Wie bereits erwähnt gleicht sich der Viewdesigner bei den lokalen Tabellen und den sogenannten Remote Tabellen.

Remote Tabellen sind alles, was man über ODBC ansprechen kann. Inzwischen liegt einem beinahe die gesamte Welt offen und jeder Datenbankhersteller bietet einen ODBC-Treiber für seine Datenbank an.

Somit haben wir unter VFP 3.0 eines der stärksten ODBC-Tools in Händen, daß zur Zeit am Markt existiert.

Hier noch ein kleiner Tip, bzw. eine Warnung.

Alle Datensätze einer View werden in einer lokalen DBF gespeichert.

Also wenn die Anzahl der Datensätze des SQL-Befehls eine Million Datensätze beträgt, so wird dementsprechend lokal eine große Menge an Plattenplatz benötigt um diese Datei unterzubringen.

Eine SELECT * FROM <Tabelle> ist also auf alle Fälle zu vermeiden. Um die Auswahl zu beschränken hat uns VFP3.0 das Fragezeichen mit auf den Weg gegeben.

Wenn in den Selektionskriterien im Feld Beispiel ein Fragezeichen eingegeben wird, so versucht die View den nachfolgenden Ausdruck als Variable zu verwerten. Ist eine Solche Variable nicht vorhanden, so bekommen Sie ein Fenster in dem Sie den Wert eingeben können.

Dadurch wird es möglich eine View sozusagen „fernzusteuern". Eine Änderung des Variablenwerts allerdings verändert nicht automatisch die View. Eine solche Aktion müssen Sie selbst durch die Funktion =REQUERY() veranlassen, daß den SQL-Befehl noch einmal ausführt.