SQL查询在酒店找到免费房间

时间:2016-03-06 19:53:30

标签: mysql sql database select

我使用查询从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 |
+-----------+------------+------------+--------+---------+

但如果我的startDate2016-03-10endDate2016-03-25 - 我已经预订了从2016-03-122016-03-22的空间。我该怎么办呢?我不需要显示我的约会之间预订的房间。

2 个答案:

答案 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 

祝你好运......