如何正确加入我的桌子?

时间:2016-01-19 10:11:30

标签: php mysql mysqli

我的数据库中有这些表。我想在2016-24-09登记入住日期和2016-26-09退房日期选择所有可用房间。

来宾表

.---------+--------------+------------+------------+--------------.
| guestID | Guest Name   |  check_in  | check_out  | date_created |
+---------+--------------+------------+------------+--------------+
|   1     | Guest 1 Name | 2016-27-09 | 2016-29-09 | 2016-10-09   |
|   2     | Guest 2 Name | 2016-30-09 | 2016-31-09 | 2016-04-09   |
.---------+--------------+------------+------------+--------------.

房间表

.---------+-----------------+-----------.
| RoomID  | RoomDetailsNo   |room_status|
+---------+-----------------+-----------
|   101   |         1       | reserved  |
|   102   |         3       | available |
|   103   |         3       | available |
|   104   |         2       | reserved  |
|   105   |         2       | available |
|   106   |         1       | available |
.---------+-----------------+-----------.

** roomdetails表**

.----------------+---------------+---------.
| RoomDetailsNo  |   room_type   |room_rate|
+----------------+---------------+---------+
|        1       | Standard Room |  3000   |
|        2       | Deluxe Room   |  3500   |
|        3       | Luxury Room   |  4000   |
.---------+-----------------+--------------.

房间保存表

.---------------+---------+--------.
| reservationID | guestID | roomNo |
+---------------+---------+--------+
|       1       |    1    |   101  |
|       2       |    2    |   104  |
.---------+--------------+---------.

我使用了这个查询

SELECT COUNT(r.roomDetailsNo) AS available_rooms, rd.roomDetailsNo, rd.room_type, rd.room_rate, 
                                        r.room_status, rd.room_pax, rd.max_cap, rd.inclusive, rd.description, g.check_in, g.check_out,
                                        rr.guestID, rr.roomNo
                                    FROM rooms AS r
                                    LEFT JOIN roomdetails AS rd
                                    ON r.roomDetailsNo = rd.roomDetailsNo
                                    LEFT JOIN roomreservation AS rr
                                    ON rr.roomNo = r.roomNo
                                    LEFT JOIN guestandreservation AS g
                                    ON rr.guestID = g.guestID
                                    WHERE r.room_status = 'available' OR (g.check_in > $new_checkOut AND g.check_in > $new_checkIn AND r.room_status = 'reserved')
                                        OR (g.check_out > $new_checkIn AND g.check_out > $new_checkOut AND r.room_status = 'reserved')
                                    GROUP BY room_type;

假设我是新客人,我将预订,那些房间101可用到2016-27-09和104至2016-30-09,我预订2016-24-09至2016-26 -09。如果在我的登记入住和退房日期仍可使用这些可预订的房间,我怎么能把它们包括在内?我不知道我的WHERE语句是错误还是我的JOIN语句

编辑:我最初没有将日期创建行包括在内,因为我认为这是不必要的但是Guest表实际上有date_created表

2 个答案:

答案 0 :(得分:0)

好的,让我们开始列出所分配的房间。要分配必须* 的房间有预订,必须有来宾,所以简单的加入:

SELECT r.RoomID, rr.check_in, rr.check_out
FROM rooms AS r
JOIN roomreservation AS rr ON (r.RoomID = rr.roomNo)
JOIN guests AS g ON (rr.guestID = g.guestID);

现在我们要检查一段时间内没有空闲的房间(date1,date2)。这意味着我们将找到一个房间,其中date2> = check_in,date1< = check_out。如果这个房间有date2< check_in,房间还不忙;如果date1> check_out,房间已经空出来了:

        c/i             c/o
---------|---------------|------------
 d1...d2
 d1............d2                      
             d1.......d2
             d1..............d2
                             d1....d2

所以房间不是免费的

SELECT DISTINCT r.RoomID
FROM rooms AS r
JOIN roomreservation AS rr ON (r.RoomID = rr.roomNo)
JOIN guests AS g ON (rr.guestID = g.guestID)
WHERE date2 >= check_in AND date1 <= check_out; 

现在我们想要免费的房间。这些是加入上面的失败加入的房间。然后我们需要LEFT JOIN。

SELECT rf.* FROM rooms AS rf
LEFT JOIN (
   SELECT DISTINCT r.RoomID
   FROM rooms AS r
   JOIN roomreservation AS rr ON (r.RoomID = rr.roomNo)
   JOIN guests AS g ON (rr.guestID = g.guestID)
   WHERE date2 >= check_in AND date1 <= check_out;
) AS rb ON (rf.RoomID = rb.RoomID)
WHERE rb.RoomID IS NULL;

注意:重要的是每位客人只有一次入住/结账,所以这很好:

GuestID    Name             CI      CO
1          Mario Rossi      12/9    12/15
2          Mario Rossi      12/20   12/25

但这很糟糕:

GuestID    Name             CI      CO
1          Mario Rossi      12/9    12/15
1          Mario Rossi      12/20   12/25
^--- 

也许您可以通过使用另一个表来存储客人的详细信息,或者更好的是将签到和结账移动到预订表中来提供更好的服务。

答案 1 :(得分:0)

  1. 我不完全理解room表中room_status字段的含义。没有与此状态标志关联的日期范围,因此很难在没有任何背景信息的情况下解释其含义。所以,我没有在where子句中触及关于此字段的代码。

  2. 您的表格结构似乎没有意义。您将签入和签出日期存储在来宾表中,而不是存储在预订表中。如果同一位客人想同时预订超过1张怎么办?你打算在不同的客人ID下记录同一位客人吗?如果同一位客人想要返回并进行后续预订怎么办?您想丢失有价值的客人历史数据吗?

  3. 首先,您必须确定哪些房间不适用于建议的预订期间,并从所有房间中减去此列表

  4. SELECT r.RoomId, rd.room_type, rd.room_rate, r.room_status FROM (rooms AS r INNER JOIN roomdetails AS rd) ON r.roomDetailsNo = rd.roomDetailsNo --I would not expect to have rooms without an appropriate roomdetails record LEFT JOIN (SELECT DISTINCT rr.roomNo FROM roomreservation AS rr LEFT JOIN guestandreservation AS g ON rr.guestID = g.guestID WHERE r.room_status = 'reserved' --I'm not touching this condition and this condition applies to all following conditions AND ((g.check_in between $out AND $in) --existing checkin overlaps OR (g.check_out between $in AND $out) -existing checkout overlaps OR (g.check_in$out)) -- existing reservation is within the proposed booking range ) as reserved ON reserved.roomNo = r.roomNo --end of subquery, join condition to outer query WHERE reserved.roomNo is null --there is no reservation for the given roomNo

    您可以将上述查询用作子查询,并按房间类型获取可用房间的数量。我从查询中删除了您提供的示例数据中没有的字段。

    确定哪个房间在该时段内首先被保留而不是确定哪些房间可用的原因是,查询只能评估房间的特定预订是否与建议的预订重叠,但无法判断是否没有其他房间。现有的房间预订将从可用房间列表中删除该房间。