Alle Tage zwischen zwei Datumsangaben in Datenbank speichern - mittels PostgreSQL

Frinias

Benutzer
Beiträge
5
Hallo zusammen,

bei meinem aktuellen Projekt sollen wir von der Schule aus eine Website aufsetzen, bei der man eine Ferienwohnung reservieren kann.
Über einen normalen Registrierungsprozess habe ich bereits alle persönlichen Daten, sowie An- und Abreisedatum (Start- und Enddatum) in die Datenbank aufgenommen.
Was bisher fehlt, sind alle Tage, die evtl. zwischen An- und Abreise liegen. Auch sie müssen beleget werden, damit es anderen nicht möglich ist, in diesem Zeitraum zu reservieren. Könnt ihr mir vielleicht bei dem Problem helfen?

Beste Grüße
Frinias
 
Werbung:
Hmm, eigentlich brauchst Du das nicht.

In Postgres kann man ein Constraint definieren welches überlappende Zeiträume automatisch verhindert. So ähnlich wie ein unique constraint aber eben für Zeiträume, nicht für einzelne Werte.
 
eine Extension installieren, und
Hmm, eigentlich brauchst Du das nicht.

In Postgres kann man ein Constraint definieren welches überlappende Zeiträume automatisch verhindert. So ähnlich wie ein unique constraint aber eben für Zeiträume, nicht für einzelne Werte.

Soweit ich weiß, braucht man dazu eine Extension?
btree_gist...

(Nutze ich zumindest bei meiner guten alten Mimoso-Datenbank ^^), wurde mir auch vom mr. Elephant so empfohlen :(

Code:
create extension btree_gist;

Danach einfach in der umfangreichen Doku schauen:

EDIT:
Auch, wenn es ohne Extension funktioniert, in der Doku stände wohl der Rest :D
 
Um das mal einfach zu erklären: in PostgreSQL gibt es viele coole Dinge, wir picken uns das raus, was wir brauchen:

  • einen Datentyp DATERANGE, welcher in einem Feld 4 Informationen speichert: von_datum, bis_datum sowie ob die Grenzen inklusive oder exlusive sind. Das sieht dann z.B. so aus: [2022-01-01,2022-01-31) '[' bedeutet inklusive, 2022-01-01 ist von, 2022-01-31 ist bis und ')' bedeutet exclusive. Also, eine Buchung in dieser Notation beginnt am 1.1. inklusive (Nach) und geht bis zum 31.1. exklusive, also ohne Nacht.
  • einer Extension btree-gist, welche die Möglichkeit gibt, Indexe zu erstellen, die sowohl BTREE-Features haben (also ganz normale Indexe), aber auch GiST-Features. GiST kommt aus der räumlichen Geometrie, GiST-Indexe können damit Indexbasiert und sehr schnell z.B. auf Überlappung prüfen
  • einem EXCLUSION CONSTRAINT, der index-basiert (und damit sehr schnell) verhindert, daß sich Objekte überlappen.

Und hier alles zusammen:

Code:
edb=*# create extension btree_gist;
FEHLER:  Erweiterung »btree_gist« existiert bereits
-- hatte ich schon installiert, daher der Fehler

edb=*# create table fewo(id int primary key, fewo int, belegt daterange, exclude using gist (fewo with =, belegt with &&));
CREATE TABLE
edb=*# 
edb=*# 
edb=*# insert into fewo values (1, 1, '[2022-01-01, 2022-01-31)');
INSERT 0 1
edb=*# insert into fewo values (2, 1, '[2022-03-01, 2022-03-31)');
INSERT 0 1

-- bis hierher habe ich jetzt die Fewo Nr. 1 zu 2 Zeiträumen verbucht
-- jetzt der Versuch einer Doppelbuchung

edb=*# insert into fewo values (3, 1, '[2022-02-25, 2022-03-05)');
FEHLER:  kollidierender Schlüsselwert verletzt Exclusion-Constraint »fewo_fewo_belegt_excl«
DETAIL:  Schlüssel (fewo, belegt)=(1, [25-FEB-22,05-MAR-22)) kollidiert mit vorhandenem Schlüssel (fewo, belegt)=(1, [01-MAR-22,31-MAR-22)).

Was auch geht: du kannst prüfen, ob ein bestimmtes Datum in einer Fewo frei oder belegt ist:

[code]
test=# select * from fewo where belegt @> '2022-01-05'::date;
 id | fewo |         belegt          
----+------+-------------------------
  1 |    1 | [2022-01-01,2022-01-31)
(1 row)

Du kannst auch fragen, ob eine bestimmte Zeit sich mit einer Buchung überlappt:

Code:
test=# select *, belegt && ('[2022-02-05,2022-02-15)')::daterange from fewo;
 id | fewo |         belegt          | ?column? 
----+------+-------------------------+----------
  1 |    1 | [2022-01-01,2022-01-31) | f
(1 row)

test=# select *, belegt && ('[2022-01-05,2022-01-15)')::daterange from fewo;
 id | fewo |         belegt          | ?column? 
----+------+-------------------------+----------
  1 |    1 | [2022-01-01,2022-01-31) | t
(1 row)


Wenn Du also 5 Fewos hast, aber nur 1 hier auftaucht, könntest Du die anderen 4 anbieten.
 
Hallo zusammen,

bei meinem aktuellen Projekt sollen wir von der Schule aus mittels PostgreSQL eine Website aufsetzen, bei der man eine Ferienwohnung reservieren kann.
Über einen normalen Registrierungsprozess habe ich bereits alle persönlichen Daten, sowie An- und Abreisedatum in die Datenbank aufgenommen.
Was bisher fehlt, sind alle Tage, die evtl. zwischen An- und Abreise liegen. Auch sie müssen beleget werden, damit es anderen nicht möglich ist, in diesem Zeitraum zu reservieren. Dabei komme ich nicht weiter. Könnt ihr mir vielleicht bei dem Problem helfen?

Beste Grüße
Frinias
 
Du musst in Postgres nicht für jeden Tag einen Datensatz speichern. In Postgres kann man constraints anlegen, die genau derartige überlappende Bereiche verhindern können. Ähnlich wie ein Unique Index.
 
Werbung:
ich ärgere mich, daß ich meine bisherigen Antworten mir nicht lokal gespeichert habe, irgendwie verschwindet heute alles hier ...

In PostgreSQL kannst Du diverse Features nutzen:

  • DATERANGE als Datentyp für Zeiträume, siehe 8.17. Range Types
  • spezielle Indexe, die Indexmethoden von Btree und GiST vereinen. DATERANGES werden intern wie eine Art Fläche angesehen, daher braucht man hier Indexmethoden aus der Geometrie ...
  • eine Erweiterung von UNIQUE, also Eindeutig, zu 'Bereiche dürfen sich nicht überlappen', EXCLUSION CONSTRAINT genannt

Code:
test=# create extension btree_gist;
CREATE EXTENSION
test=# create table fewo(id int primary key, fewo int, belegt daterange, exclude using gist (fewo with =, belegt with &&));
CREATE TABLE
test=# insert into fewo values (1, 1, '[2022-01-01, 2022-01-31)');
INSERT 0 1
test=# insert into fewo values (2, 1, '[2022-03-01, 2022-03-31)');
INSERT 0 1
test=# insert into fewo values (3, 1, '[2022-01-10, 2022-02-10)');
ERROR:  conflicting key value violates exclusion constraint "fewo_fewo_belegt_excl"
DETAIL:  Key (fewo, belegt)=(1, [2022-01-10,2022-02-10)) conflicts with existing key (fewo, belegt)=(1, [2022-01-01,2022-01-31)).

Zuerst die Extension, die ist in einer Standard-Installation mit dabei, aber nicht aktiv. Beim create table dann mit 'belegt' als Datentyp daterange, und der exclusion constraint, der die fewo mit Gleichheit prüft (=) und belegt auf Überlappung (&& ist der Überlappungsoperator).

Du kannst auch prüfen, was in einem Zeitraum belegt ist, hier für 5.1. bis 15.1. und vom 5.5. bis 15.5.:

Code:
test=# select * from fewo where belegt && ('[2022-01-05,2022-01-15)')::daterange;
 id | fewo |         belegt          
----+------+-------------------------
  1 |    1 | [2022-01-01,2022-01-31)
(1 row)

test=# select * from fewo where belegt && ('[2022-05-05,2022-05-15)')::daterange;
 id | fewo | belegt 
----+------+--------
(0 rows)

etc.



Vielleicht kann ja der Admin die 'verschwundenen' Antworten noch mal wiederbeleben und hier anzeigen...
 
Zurück
Oben