reservation overlap constraint checking?

From: Aditya <aditya(at)grot(dot)org>
To: sfpug(at)postgresql(dot)org
Subject: reservation overlap constraint checking?
Date: 2005-05-20 16:25:08
Message-ID: 20050520162508.GA87868@mighty.grot.org
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: sfpug

This must be a classic SQL/RDBMS design problem yet I can't find any good
"cookbook" descriptions on how best to do it.

The problem is simple, there are a bunch of resources that can be reserved for
arbitrary time periods and I have to make sure there are no overlapping
reservations (think hotel rooms, but in this case it is an LCD projector):

grot=> \d go_reserve
Table "public.go_reserve"
Column | Type | Modifiers
------------+--------------------------+---------------------------------
resource | bigint |
username | text |
start_time | timestamp with time zone | not null default now()
end_time | timestamp with time zone | not null default now()
status | text | not null default 'ACTIVE'::text
inserted | timestamp with time zone | not null default now()
updated | timestamp with time zone | not null default now()
updatedby | text | not null
Check constraints:
"end_gt_start" CHECK (end_time > start_time)
Foreign-key constraints:
"$1" FOREIGN KEY (resource) REFERENCES go_resource(id)
"$2" FOREIGN KEY (username) REFERENCES bloki_user(username)

grot=> select * from go_reserve ;
resource | username | start_time | end_time | status | inserted | updated |
updatedby
----------+----------+-------------------------------+-------------------------------+--------+-------------------------------+-------------------------------+-----------
1 | aditya | 2005-05-12 13:42:50.158781-04 | 2005-051 313:42:50.158781-04 | ACTIVE | 2005-05-19 13:42:50.158781-04 | 2005-05-1913:42:50.158781-04 | aditya
1 | aditya | 2005-05-19 10:43:20.889513-04 | 2005-05-1911:43:20.889513-04 | ACTIVE | 2005-05-19 13:43:20.889513-04 | 2005-05-1913:43:20.889513-04 | aditya
1 | aditya | 2005-05-19 16:43:38.778486-04 | 2005-05-1917:43:38.778486-04 | ACTIVE | 2005-05-19 13:43:38.778486-04 | 2005-05-1913:43:38.778486-04 | aditya
1 | aditya | 2005-05-19 18:43:50.168998-04 | 2005-05-1919:43:50.168998-04 | ACTIVE | 2005-05-19 13:43:50.168998-04 | 2005-05-1913:43:50.168998-04 | aditya
(4 rows)

So postgresql has the "overlaps" operator

http://www.postgresql.org/docs/7.4/static/functions-datetime.html

that works with timestamps, so I can do things like

grot=> select case when ('2005-05-19 18:45:00'::timestamp, '2005-05-19
18:50:00'::timestamp) overlaps (start_time, end_time) then 'unavailable' else
'available' end from go_reserve where resource = 1 and status = 'ACTIVE';
case
-------------
available
available
available
unavailable
(4 rows)

so I can do it such that I run a query first to find if there are any
overlaps, and if that returns no overlaps, then I insert:

grot=> select count(*) from go_reserve where (('2005-05-19
18:41:00'::timestamp, '2005-05-19 18:42:00'::timestamp) overlaps (start_time,
end_time) = true) and resource = 1 and status = 'ACTIVE';
count
-------
0
(1 row)

however, that seems less than elegant because there is time between the check
and the insert for a competing entry to get inserted....so next thing to try
is a constratint:

alter table go_reserve add constraint no_overlaps check (!(select (start_time,
end_time) overlaps (select start_time, end_time from go_reserve where
start_time >= now() and status = 'ACTIVE')));

but postgresql doesn't like selects in a constraint...

clues?

Thanks,
Adi

Responses

Browse sfpug by date

  From Date Subject
Next Message Josh Berkus 2005-05-20 18:29:11 Re: reservation overlap constraint checking?
Previous Message Sam Hahn 2005-05-20 05:23:54 Re: Party in south bay with Bruce?