Monday, August 04, 2008 7:02 PM
SergeyS
A T-SQL simple puzzle on ASP.NET forum.
http://forums.asp.net/p/1299660/2535207.aspx#2535207
Lets say that I've got two tables:
ROOM:
ID_ROOM : int
Name: Nvarchar(50)
RESERVATION
ID_RESERVATION : int // unique ID of reservation
ID_ROOM : int // which room is reserved
DATE: SmallDateTime // date of reservation
HOUR_BEGINNING : int // hour in which reservation begin
HOUR_END : int // hour in which reservation end
And now I want to find ALL rooms which can be reserved for at least DURATION(int) hours between HOUR_SEEK_START(int) and HOUR_SEEK_END(int) in day DAY(SmallDateTime). For example: I want to find all rooms which can be reserved for at least 2 hours between 10 and 16 on 16.05.2008. I hope I set the record straight.
My reply was:
---
First, let's cast the phrase "for at least DURATION(int) hours between HOUR_SEEK_START(int) and HOUR_SEEK_END(int)" into something set oriented. Why not create a temp table to keep potentially good time intervals, those of DURATION(int) length that could fit between HOUR_SEEK_START(int) and HOUR_SEEK_END(int). Later for each room we'll just check out if among these intervals there will be one not spoiled by related reservation records.
CREATE TABLE #Hours(
IndexId int IDENTITY (0, 1) NOT NULL,
hr nchar(8))
INSERT INTO #Hours(hr) VALUES ('0'); INSERT INTO #Hours(hr) VALUES ('1');
INSERT INTO #Hours(hr) VALUES ('2'); INSERT INTO #Hours(hr) VALUES ('3');
INSERT INTO #Hours(hr) VALUES ('4'); INSERT INTO #Hours(hr) VALUES ('5');
INSERT INTO #Hours(hr) VALUES ('6'); INSERT INTO #Hours(hr) VALUES ('7');
INSERT INTO #Hours(hr) VALUES ('8'); INSERT INTO #Hours(hr) VALUES ('9');
INSERT INTO #Hours(hr) VALUES ('10'); INSERT INTO #Hours(hr) VALUES ('11');
INSERT INTO #Hours(hr) VALUES ('12'); INSERT INTO #Hours(hr) VALUES ('13');
INSERT INTO #Hours(hr) VALUES ('14'); INSERT INTO #Hours(hr) VALUES ('15');
INSERT INTO #Hours(hr) VALUES ('16'); INSERT INTO #Hours(hr) VALUES ('17');
INSERT INTO #Hours(hr) VALUES ('18'); INSERT INTO #Hours(hr) VALUES ('19');
INSERT INTO #Hours(hr) VALUES ('20'); INSERT INTO #Hours(hr) VALUES ('21');
INSERT INTO #Hours(hr) VALUES ('22'); INSERT INTO #Hours(hr) VALUES ('23');
CREATE TABLE #TimeSpansRequested(hr1 int, hr2 int)
INSERT INTO #TimeSpansRequested(hr1, hr2)
SELECT h1.IndexId, h2.IndexId
FROM #Hours h1, #Hours h2
WHERE (h2.IndexId - h1.IndexId = @DURATION)
AND (h1.IndexId BETWEEN @HOUR_SEEK_START AND (@HOUR_SEEK_END - @DURATION))
The above T-SQL code is self explaining. We self joined #Hours temp table to get a set of time intervals, and then restricted the intervals to those of @DURATION length that are between @HOUR_SEEK_START and @HOUR_SEEK_END hours. The result is getting into #TimeSpansRequested temp table. Its records are just pairs of (hr1, hr2) hours - borders of pottentially good intervals. And finally:
SELECT *
FROM ROOM
WHERE EXISTS(SELECT hr1
FROM #TimeSpansRequested
WHERE NOT EXISTS(SELECT ID_TIMESPAN
FROM RESERVATION
WHERE (RESERVATION.ID_OBJ = ROOM.ID_OBJ)
AND ([DATE] = @DAY)
AND ((hr1 BETWEEN HOUR_BEGINNING AND HOUR_END)
OR (hr2 BETWEEN HOUR_BEGINNING AND HOUR_END))
)
)
In the code above we are checking out for each door if exists some potentially good interval that is not spoiled by any of reservation timespan.
Filed under: General Software Development, SQL Server, T-SQL