Spielereien mit Rules und Check Constraints in PostgreSQL


Ich hatte heute das Problem, daß ich in der Datenbank Zeiträume (Start- und Enddatum) speichern mußte, in denen bestimmte Resourcen in Benutzung sind/sein werden. Eine Resource darf dabei zu einem bestimmten Zeitpunkt nicht mehrfach belegt werden. Ich mußte also sicherstellen, daß sich die Zeitbereiche einer Resource nicht überlappen.

Check Constrainst von PostgreSQL alleine hilft da leider nicht. Der kann nur auf Konsistenz innerhalb eines Datensatzen prüfen, z.B. ob das Startdatum vor dem Enddatum liegt. Soll geprüft werden, ob die neu einzufügenden Daten in irgendeiner Beziehung zu bereits vorhanden Daten stehen, so müssen Regeln (RULE) definiert werden. Dies sieht in meinem Beispiel so aus.

CREATE TABLE sometable (
	id				serial,
	start_date			date		NOT NULL,
	end_date			date		NOT NULL,
	resource			integer	NOT NULL,
	CHECK (start_date<=end_date)
);
CREATE RULE no_overlap_insert AS ON INSERT TO sometable
WHERE EXISTS (
	SELECT * FROM sometable
	WHERE ((( new.start_date>=start_date AND new.start_date<=end_date )
		OR ( new.end_date>=start_date AND new.end_date<=end_date ))
	  AND new.resource=resource)
)
DO INSTEAD NOTHING;

Hier habe ich also ein Check Constrainst, das prüft, ob das Startdatum auch wirklich vor dem Enddatum liegt sowie eine Regel, die verhindert, daß ich eine Resource zu einer Zeit mehrfach belege.

Unschön an dieser Lösung ist jedoch, daß der Check Constrainst einen Fehler hervorruft, wenn die Bedingung nicht erfüllt wird, während die Regel einfach still die Daten verwirft. Man kann also nur anhand der Anzahl der geänderten Datensätze, die nach jedem INSERT/UPDATE zurückgegeben wird, feststellen, ob die Daten erfolgreich gespeichert wurden. Hier wäre es natürlich angenehmer, wenn auch ein Fehler erzeugt würde.

Nicht im Beispiel enthalten ist eine zweite Regel, die verhindert, daß man bereits vorhandene Datensätze so ändert, daß es doch wieder zu Überlappungen kommt. Hierzu muß einfach eine zweite Regel (mit anderem Namen) erstellt werden, die statt ON INSERT ein ON UPDATE enthält.


Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.