Guten Tag,
ich stelle mal meine Frage aus dem Lazarusforum (https://www.lazarusforum.de/viewtopic.php?f=17&t=15085) auch nochmal hier, weil ich nicht weiß ob “mein Problem” Lazarusseitig gehandhabt werden muß oder innerhalb der Datenbank gehandhabt werden kann, bzw. das DB-Design geändert werden sollte/muß.
Ich habe eine ButtonClick-Prozedur, bei der in zwei Tabellen (Tabelle_1 und Tabelle_2) nacheinander “INSERT” durchgeführt wird.
Für den Insert in Tabelle_2 ist der Primareykey aus Tabelle_1 notwendig. Den hole ich mir mit “CURRVAL” aus der Sequenz von Tabelle_1.
Das ganze läuft nacheinander durch verschiedne SQL-Zuweisungen über eine ZEOS-TZQuery-Variable (Eingabe) die ich am Anfang initialisiere und am Ende wieder frei gebe (FreeAndNil(Eingabe)).
Die nacheinander ablaufenden Vorgänge sind in einem try-except-Block verpackt.
Tabelle_2 hat jetzt eine UNIQUE-Constraint, die nicht verletzt werden darf. Wenn sie Verletzt wird, dann tritt der except-Fall ein und eine Fehlermeldung wird geworfen. Die Änderung an Tabelle_2 findet nicht statt, wird zurückgewiesen. Allerdings zählt das Autoincrement von Tabelle_2 trotzdem hoch. Das kann man mit PGAdmin nachvollziehen.
Nach dem Zurückweisen müssten drei Dinge rückgängig gemacht werden (von hinten nach vorne):
1.) Das Increment von Tabelle_2 wieder um 1 reduzieren um den Wert nicht zu vergeuden.
2.) Den Eintrag in Tabelle_1 wieder löschen und 3.) auch dort das Increment der Sequenz um 1 reduzieren. Die wurde ja auch hochgezählt.
Ich dachte an einen Trigger in Postgres, aber der müsste auf die Unique-Verletzung von Tabelle_2 reagieren. Die Trigger reagieren aber auf BEFORE/AFTER INSERT/UPDATE/DELETE
DELETE des Datensatz an Tabelle_1 müsste dann die Folge des Triggers sein. Den Datensatz löschen und beide Autoincremente um 1 reduzieren.
Die UNIQUE-Bedingung von Tabelle_2 sind eine Datumsspalte und eine Nummernspalte. Jede Nummer darf es zu jedem Datum nur einmal geben.
Wie löst man sowas?
Ist die Vorgehensweise überhaupt sinnvoll für Mehrbenutzerbetrieb? Es sind zwar nur zwei bis drei Benutzer die parallel Eingaben vornehmen würden und es erscheint unwahrscheinlich dass zwei Nutzer absolut zeitgleich ihre “Inserts” an die Tabellen losschicken. Aber wenn Nutzer 1 seine “Inserts” losschickt bekommt er über CURRVAL ja den Sequenzwert zurück mit dem die zweite Tabelle gefüttert wird. Kann man davon ausgehen, dass Postgres das richtig macht und jedem die richtigen Sequenzwerte mitgeteilt werden? Oder kann das zu Durcheinander führen? Im Einzelnutzerbetrieb funktioniert die Vorgehensweise tadellos, bis auf den Fall, dass man sich ggf. vertut und eine bereits vergebende Nummer nochmal verwendet werden soll.
Ich kann natürlich die UNIQUE-Bedingung rausnehmen und doppelte Nummern zulassen. Das müsste dann nachträglich händisch in der Übersichtstabelle mit den Augen erkannt und entsprechend korrigiert werden, aber ich wollte diesen möglichen Bedienerfehler software- bzw. db-seitig abfangen.
Wenn in andern Feldern Mist eingetragen wird ist das nicht tragisch. Per Update-Befehl auf die DB ist das einfach zu korrigieren. Eine Update-Prozedur gibt es, zumal bei Anlage der Datensätze nicht zwingend schon alle Informationen bekannt sind und nachträglich ergänzt werden müssen.
Vielen Dank für Eure Meinungen