MichaelR: Konzept: Terminreservierung - Doppel-Termin-Vergabe vermeiden

Hallo liebes Forum,

für zwei meiner Terminvergabetools nutze ich nachfolgend beschriebenes Vorgehen, um Doppelbuchungen eines Termins (Uhrzeit + Tag) zu vermeiden. Mich würde interessieren, welche besseren Vorgehensweisen es noch gibt...

Vorgehen: Nutzer wählt einen Termin (Uhrzeit + Tag) aus; diese Daten werden an das PHP-Backend gesendet und dort prüft eine Routine, ob diese Termin-Kombination bereits durch eine andere Person vergeben ist. Hierzu werden alle vergebenen Termine am Server gespeichert und die Routine gleicht die gesendeten Daten damit ab. Ist der Termin bereits vorhanden, wird ein entsprechender Fehler gemeldet. Ansonsten wird der Termin für diese Person gespeichert und die "Nachschlage"-Liste aktualisiert

Dass zwei oder mehr Personen gleichzeitig den gleichen Termin anfragen und es damit zu Doppelbuchungen kommt, ist aufgrund es Einsatzgebietes eher unwahrscheinlich...

Wie könnte man das eventuell noch (eleganter?) lösen?

Danke und viele Grüße MichaelR

  1. Hallo Michael,

    die Frage ist hier, ob Du ein festes Terminraster hast, mit festen Terminlängen, oder ob Termine relativ frei beginnen und enden können.

    Bei einem festen Terminraster würde ich empfehlen, einfach Datum und Uhrzeit als eindeutigen Index zu definieren - bei einem Duplikat schlägt dann der INSERT Befehl einfach fehl und gut ist.

    Bei einem variablen Raster wird es schwieriger.

    Letztlich musst Du ja nur wissen, ob es für den gewünschten Zeitraum keine Überlappungen gibt. D.h. jeder Termin in der Tabelle muss einen Ende-Zeitpunkt haben, der vor deinem Startzeitpunkt liegt ODER einen Start-Zeitpunkt, der hinter deinem Endezeitpunkt liegt. Ob "vor" und "hinter" nun als < und > oder als <= und >= zu implementieren sind, musst Du Dir überlegen.

    Wenn Du einen Termin (newStart, newEnde) hast, wäre ein Termin aus der Tabelle t mit (t.start, t.ende) also kollisionsfrei, wenn gilt:

    t.ende <= newStart OR t.start >= newEnde
    

    Du musst aber das Gegenteil finden. Zeit für den Kollegen De Morgan:

    NOT( t.ende <= newStart OR t.start >= newEnde )
    

    wird zu

    NOT( t.ende <= newStart ) AND NOT( t.start >= newEnde )
    

    wird zu

    t.ende > newStart AND t.start < newEnde
    

    Ich kriege Kopfschmerzen, wenn ich das anschaue, aber ich vertraue der De Morgan Regel 😉

    Also:

    SELECT COUNT(*)
    FROM termine t
    WHERE t.ende > newStart AND t.start < newEnde
    

    liefert Dir die Anzahl der kollidierenden Termine (wobei Du newStart und newEnde mit geeigneten Mitteln in die Query einsetzen musst). Leg einen Index auf (t.start, t.ende) und das Ganze sollte akzeptabel schnell sein.

    Und dann würde ich stumpf die Tabelle sperren:

    LOCK TABLES termine WRITE
    SELECT COUNT(*)...
    
    Wenn Ergebnis 0 ist
       INSERT
    
    UNLOCK
    

    Wenn der LOCK WRITE die regulären Terminabfragen zu sehr behindert, dann führe eine Dummy-Tabelle ein, wo nichts drin steht, und die Du vor Terminupdates lockst. Das muss dann aber sehr konsequent passieren, jeder INSERT und jeder UPDATE auf start oder ende muss vorher die Dummy-Table locken.

    Wenn wirklich viel los ist auf der Termine-DB, mag das immer noch zu Engpässen führen und man muss sich ggf. andere Datenstrukturen überlegen. Aber nur dann.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Hallo Rolf,

      vielen Dank für die prima Antwort!

      Beste Grüße Michael

  2. Moin,

    Wie könnte man das eventuell noch (eleganter?) lösen?

    Mit welcher Datenbank? PostgreSQL kennt Range-Typen als Spaltentyp welche auch in Constraints verwendet werden können womit Doppeleintragungen nicht möglich sind – selbst getestet habe ich das aber noch nicht, nur darüber gelesen.

    Gruß
    Tobias