这是查询的工作原理,并已经过任何其他职位空缺组合的测试。任何事情之后空缺。在现有开始之前,之后开始日期。结束日期在现有结束日期之前,之后。完全跨在另一个预订之外。完全在另一个预订。
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
然后我用下面的预订日期检测,符合下列有效空缺VS冲突,并已经被占用了上来。此测试仅适用于单人房间,但显然适用于酒店的任何房间。
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子句。所以我不必像存储过程那样“声明”变量,我正在通过@parmStartDate,@parmEndDate进行IN-LINE操作,并为了声明目的分配别名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月等等退房?所以现在,你走多远......你也只关心那些下一个现有预订有开始日期最多的记录您将要退房的那一天。所以,如果7月6日检查,你不关心7月7日或之后的任何预订。到现在为止还挺好。
现在,我来了解如何知道房间是否被占用。我在比较现有的开始日期和查找日期方面遇到了困难,并且得到了错误的答案,所以我不得不求助于日期数学,并将开始时间和结束时间以及结束时间进行比较以开始,如果乘数结果为正数,则会出现冲突。
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
好运...
如果事件A在事件B结束之前开始并且在事件B开始之后结束,则事件A与事件B重叠。 – Strawberry
@Strawberry像这样,其中'3-8-2016'选择开始和'3-15-2016'选择结束? 'SELECT * FROM b WHERE 3-8-2016 <= startDate AND endDate <='3-15-2016'OR'3-8-2016'> = startDate AND endDate> ='3-15-2016'OR'3 -816'> = startDate AND endDate <='3-15-2016'AND(startDate> = NOW()AND endDate> = NOW())OR'3-8-2016'<= startDate AND endDate> = '3-15-2016'和((''3-8-2016'在startDate和endDate之间)或('3-15-2016'在startDate和endDate之间))' – rel1x
编号重新阅读我的评论。 – Strawberry