我使用查询从hotel
数据库中查找免费房间。我写了一个查询,选择不在booking
表中的房间:
SELECT * FROM room WHERE roomId NOT IN
(SELECT roomId FROM booking b WHERE STR_TO_DATE('${endDate}', '%m-%d-%Y') <= b.endDate AND
STR_TO_DATE('${startDate}', '%m-%d-%Y') >= b.startDate);
我的booking
表格如下:
+-----------+------------+------------+--------+---------+
| bookingId | startDate | endDate | roomId | guestId |
+-----------+------------+------------+--------+---------+
| 1 | 2016-03-12 | 2016-03-22 | 1 | 1 |
+-----------+------------+------------+--------+---------+
但如果我的startDate
为2016-03-10
且endDate
为2016-03-25
- 我已经预订了从2016-03-12
到2016-03-22
的空间。我该怎么办呢?我不需要显示我的约会之间预订的房间。
答案 0 :(得分:3)
查找范围内免费房间问题的一般方法($ BOOKING_BEGIN&lt; =&gt; $ BOOKING_END)如下:
SELECT
rooms.room_id
FROM
rooms
LEFT JOIN
bookings
ON (
bookings.room_id = rooms.room_id AND
NOT (
(bookings.begin < $BOOKING_BEGIN and bookings.end < $BOOKING_BEGIN)
OR
(bookings.begin > $BOOKING_END and bookings.end > $BOOKING_END)
)
)
WHERE
bookings.room_id IS NULL;
这仅仅意味着占用酒店的所有房间,并加入已预订的房间。如果有空,则表示在给定范围内房间是免费的(加入并未找到现有预订)。
答案 1 :(得分:1)
这是有效的查询,并且已经针对任何其他空缺的所有组合进行了测试。什么都有空缺。在现有开始之前,之后,开始日期。结束日期在现有结束日期之前,之后,之后。完全跨越另一个预订。完全在另一个预订中。
select
r.RoomID
from
Room r
LEFT JOIN
( select
b.RoomID
from
booking b,
( select @parmStartDate := '2016-01-21',
@parmEndDate := '2016-01-23' ) sqlvars
where
b.EndDate >= @parmStartDate
AND b.StartDate <= @parmEndDate
AND ( timestampdiff( day, b.StartDate, @parmEndDate )
* timestampdiff( day, @parmStartDate, b.EndDate )) > 0 ) Occupied
ON r.RoomID = Occupied.RoomID
where
Occupied.RoomID IS NULL;
我创建的样本预订数据包括
BookID RoomID StartDate EndDate
1 1 2016-02-03 2016-02-04
2 1 2016-02-04 2016-02-08
3 1 2016-02-12 2016-02-16
4 1 2016-02-20 2016-02-28
然后,我在以下预订日期进行测试,并得出以下有效空缺与冲突并已被占用。此测试仅适用于单个房间,但显然适用于酒店的任何房间。
Both dates before anything on file... Room available
2016-01-10 - 2016-01-15
Both dates after anything on file... Room available
2016-03-10 - 2016-03-15
Occupied ID 1 -- Same start date
2016-02-03 - 2016-02-04
Occupied ID 2 -- Same start date, but less than existing occupied end date
2016-02-04 - 2016-02-05
Occupied ID 2 -- Same start, Exceeds end occupancy date
2016-02-04 - 2016-02-09
Occupied ID 3 -- Start before, but end date WITHIN existing booking
2016-02-09 - 2016-02-13
Available. The END Date is the START Date of the existing booking
(Between 2 & 3 booking)
2016-02-09 - 2016-02-12
Occupied ID 3 -- Started within date, but end outside existing booking
2016-02-15 - 2016-02-17
Available. End of existing booking and nothing booked on 2/17
2016-02-16 - 2016-02-17
Occupied ID 3 -- Completely encompasses booking entry
2016-02-11 - 2016-02-17
Occupied ID 4 -- totally WITHIN another entry
2016-02-21 - 2016-02-23
现在,解释发生了什么。我做了LEFT-JOIN并寻找NULL(即:没有其他预订的冲突),这与你的NOT IN子选择非常相似。所以我将跳过那一部分。
首先是FROM子句。所以我没有&#34;声明&#34;像存储过程这样的变量,我通过@parmStartDate,@ parmEndDate在线进行,并为了声明目的而分配别名sqlvars。由于这会返回一行,因此将笛卡尔应用于预订表是没有问题的。
from
booking b,
( select @parmStartDate := '2016-01-21',
@parmEndDate := '2016-01-23' ) sqlvars
现在,WHERE子句。如果您的餐桌有超过几年的预订时间和100多个房间,这可能会很快变得非常大,所以我想预先开始只有那些现有预订将会到位的日期
where
b.EndDate >= @parmStartDate
AND b.StartDate <= @parmEndDate
至少,我只关心那些现有结帐日期至少是您尝试查找可用性的日期的预订。例如:您正在寻找7月4日的入住日期。如果有人在2月,3月,4月等检查过,你为什么还要关心...所以现在,你走多远...你也只关心那些下一个现有预订有START Date UP TO的记录你要退房的那一天。因此,如果在7月6日退房,您不会关心7月7日或之后的任何预订。到目前为止,非常好。
现在,我怎么知道房间是否被占用。我在比较现有的开始日期和查找日期时遇到了困难,并且得到了错误的答案,所以我不得不求助于日期数学并比较开始到结束和结束开始,如果乘数结果为正,则存在冲突。 / p>
AND ( timestampdiff( day, b.StartDate, @parmEndDate )
* timestampdiff( day, @parmStartDate, b.EndDate )) > 0 )
由于我们已经知道我们在可能的日期范围内有记录,因此这是在完全外部,内部,冲突左或冲突权利的任一方向进行冲突检查。它只是有效。
您必须看到它才能更好地理解它,这是我运行的查询,因此您可以自己查看结果。只需插入您要查找的相应开始/结束日期即可。
select
b.BookID,
b.RoomID,
b.StartDate,
b.EndDate,
@parmStartDate as pStart,
@parmEndDate as pEnd,
( timestampdiff( day, b.StartDate, @parmEndDate )
* timestampdiff( day, @parmStartDate, b.EndDate )) <= 0 as Available,
( timestampdiff( day, b.StartDate, @parmEndDate )
* timestampdiff( day, @parmStartDate, b.EndDate )) > 0 as Occupied
from
booking b,
( select @parmStartDate := '2016-01-21',
@parmEndDate := '2016-01-23' ) sqlvars
祝你好运......