2016-03-06 113 views
1

我使用查询从hotel DB查找免费房间。我写了选择的房间是不是在booking表的查询:通过SQL查询在酒店中查找免费房间

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 | 
+-----------+------------+------------+--------+---------+ 

但如果我的startDate2016-03-10endDate2016-03-25 - 我有已经预订房间从2016-03-122016-03-22。我如何解决它?我不需要显示在我的日期之间预订的房间。

+1

如果事件A在事件B结束之前开始并且在事件B开始之后结束,则事件A与事件B重叠。 – Strawberry

+0

@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

+0

编号重新阅读我的评论。 – Strawberry

回答

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 

然后我用下面的预订日期检测,符合下列有效空缺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 

好运...

+0

@rel1x,在SQL中修改了查询并测试了所有具有简化参数设置的组合,以防止复杂嵌入。 – DRapp

+0

我仍然不明白为什么你有更多的查询比'where b.EndDate> = @parmStartDate AND b.StartDate <= @ parmEndDate'。这很好,并使用索引 - 哪些timestampdiff等不能 – Strawberry

+0

@Strawberry,而TIMESTAMPDIFF()不使用索引,WHERE WOULD的前一部分寻找最低日期来限定。在MySQL中,在工作台中,我正在尝试使用> =和<日期,但他们错误地回来了,例如计算数字,所以迫使日期函数起作用。从字面上看,例如:'2016-01-15'的开始被认为大于'2016-02-04',所以我必须做一个解决方法。 – DRapp

3

查找范围内免费客房的问题,一般的方法($ BOOKING_BEGIN < => $ 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; 

它只是手段'把酒店的所有房间都拿走,然后加入已经预订好的房间。如果为空,则表示房间在给定范围内免费(Join没有找到现有预订)。