Hallo Herbert
Wie kann ich einen spezifischen Datensatz aus einer
Flat-File-Datanbank in eine editierbare Tabelle abfüllen?
Falls Du die Perl-Module DBI und DBD-CSV für den Datenbankzugriff verwendest, dann kannst Du in der (fast) gleichen Art und Weise auf die Datensätze in Deiner Flat-File-DB zugreifen, wie auf einen SQL-Server. Es stehen Dir die gleichen SQL-Statements (SELECT, INSERT, UPDATE, DELETE, ...) zur Verfügung.
Mein eigentliches Problem ist, dass ich es wohl fertigbringe, einen Datensatz aus der DB auszulesen, doch WIE kann ich den betreffenden Record so markieren, dass er nach der Bearbeitung im Formular wieder zurückgeschrieben werden kann?
Wie gerhard beschrieben hat, hängt das nicht mit der Technik des Datenzugriffs zusammen, sondern mit der Datenmodellierung.
Für die eindeutige Identifizierung eines Datensatzes benötigst Du eine Feld (Tabellenspalte) mit der ID, die Du für jeden Datensatz erzeugen musst. Die ID wird mit dem SELECT-Statement ausgelesen und wird beim zurückschreiben der geänderten Formulardaten in der WHERE-Klausel des UPDATE-Statements wieder eingesetzt.
Beispiel:
SELECT id, feld1, feld2, feld3 FROM tabelle
Die id schreibst Du in ein Hidden-Field des Formulars, damit sich beim Absenden des Formulars Deinem Skript wieder zur Verfügung steht.
Die Änderungen schreibts Du dann mit dem UPdate-Statement wieder in die DB:
UPDATE tabelle SET feld1=$in{'feld1'}, feld2=$in{'feld2'}, feld3=$in{'feld3'} WHERE id=$in{'id'}
Der Hash %in enthält alle Formularfeldwerte, wie sie unter Verwendeung der cgi-lib.pl zur Vefügung gestellt werden.
Falls die Anwendung in einer Mehrbenutzerumgebung läuft, in der mehr als ein Benutzer gleichzeitig Datensätze _ändern_ darf, so muss beim Aktualisieren des Datensatzes geprüft werden, ob nicht in der Zwischenzeit der Datensätz von jemand anderem geändert wurde, bzw. der Datensatz muss während der Bearbeitung durch einen Benutzer gesperrt bleiben.
Dazu gibt es (grob, neben einigen anderen) 3 Möglichkeiten:
- Du sperrst die ganze Tabelle, sobald ein User den Datensatz zum Ändern gelesen hat. Dies sollte über flock() (File-Locking in Perl) funktionieren. Wenn selten mehrere User auf die Tabelle zugreifen, ist das ok.
- Du sperrst den zum Bearbeiten geladen Datensatz über Record-Locking. Dies muss jedoch von der DB-Engine unterstützt werden. MS Access und MS-SQL bieten etwas ähnliches unter Page-Locking. Dabei wird die interne Speicherseite (2048 Bytes) mit dem Datensatz gesperrt. Es werden also auch einige andere Datensätze in der "Umgebung" mitgesperrt. Das DBI-Modul und der DBD-CSV-Treiber für Flat-File-Tabellen unterstützt jedoch kein Sperren von Datensätzen oder ähnlichem.
- Du fügst der Tabelle ein weiteres Feld hinzu, in dem bei jeder Änderung (Erstellen + Aktualisieren) des Datensatz ein Zeitstempel (timestamp) eingetragen wird. Dieser Zeitstempel kann tatsächlich ein Datums-/Zeitwert sein, kann jedoch auch ein serverinterner Zähler sein, der bei jedem Prozessaufruf um eins hochgezahlt wird. Für nicht zu viele Änderungeszugriffe bietet sich in Perl die UTC-Zeit des Servers als Zeitstempel an. Sie wird durch $time ausgelesen und stellt die Anzahl Sekunden seit 1.1.1970 dar. Sind jedoch 2 oder mehr Aktualisierungszugriffe auf die Tabelle zu erwarten, so müssste die UTC-Zeit noch mit der Prozess-ID verknüpft werden (z.B. $time.$$). Auf jeden Fall wird bei jedem SELECT_Statement der Zeitstempel mit ausgelesen und im Formular in einem Hidden-Field zwischengespeichert. Beim Zurückschreiben der Änderungen überprüfst Du jedoch zuerst, ob der Zeitstempel im Datensatz sich verändert hat. Ist dies der Fall, so musst Du dem User eine Konfliktbehandlung anbieten. Andernfalls kannst Du die Änderung in die DB zurückschreiben.
Beispiel:
SELECT id, feld1, feld2, feld3, timestamp FROM tabelle
Den timestamp schreibst Du in ein Hidden-Field des Formulars.
Beim Abarbeiten der Formularrückgabe in deinem Skript liest Du den Zeitstempel nochmals aus:
SELECT timestamp FROM tabelle
und vergleichst Ihn mit dem Zeistempel im %in-Hash (z.B. $in{'timestamp'})
Falls die Werte gleich sind, kannst Du die Änderungen in die DB schreiben.
UPDATE tabelle SET feld1=$in{'feld1'}, feld2=$in{'feld2'}, feld3=$in{'feld3'}, timestamp=$time WHERE id=$in{'id'}
wobei hier mit $time ein neuer Zeitstempel gesetzt wird.
Bei hoher Aktualisierungshäufigkeit müsste zwischen dem 2. SELECT-Statement (bei auslesen des Zeitsstempels) und dem Zurückschreiben der Änderungen die Tabelle, bzw. der Record gesperrt werden.
Ich hoffe, mit diesen Ausführungen nicht zuviel Verwirrung gestiftet zu haben.
Wenn doch, dann kannst Du das Problem nochmals näher schildern.
Grüsse
Tom