Mysql 酒店预订系统SQL查询:确定某个特定房间何时可用

Mysql 酒店预订系统SQL查询:确定某个特定房间何时可用,mysql,sql,join,Mysql,Sql,Join,我有一个酒店预订系统的查询,我需要找到特定房间可用的日期。(这是一家精品酒店,人们在这里预订了特定的房间,因此在使用此代码之前,他们知道自己想要的确切房间。我想要的结果是一个房间的详细信息,即我在查询中指定的房间——我不查找多个房间的信息。) “可用性”表架构很简单,每行为: room_id date_occupied - a single day that is occupied (like '2011-01-01') 因此,例如,如果一个房间从1月1日到1月5日被占用,则可用性表中会添加五

我有一个酒店预订系统的查询,我需要找到特定房间可用的日期。(这是一家精品酒店,人们在这里预订了特定的房间,因此在使用此代码之前,他们知道自己想要的确切房间。我想要的结果是一个房间的详细信息,即我在查询中指定的房间——我不查找多个房间的信息。

“可用性”表架构很简单,每行为:

room_id
date_occupied - a single day that is occupied (like '2011-01-01')
因此,例如,如果一个房间从1月1日到1月5日被占用,则可用性表中会添加五行,房间被占用的每一天一行

以下是我想要解决的问题:

  • 要查找特定房间在开始日期和结束日期之间何时可用的查询,类似于:
  • 我也在寻找一个类似的查询,我只想看看在开始日期和接下来的两天是否有特定的房间,比如:
我有点想弄清楚确切的连接。有什么建议吗?请注意,如果有帮助的话,我完全愿意使用不同的可用性表模式。让查询最有效的方法。

(以下是我根据OP对标准的澄清而更新的答案)

Eric,看看下面的内容:

我的测试模式

mysql> desc rooms;
+-------+---------+------+-----+---------+----------------+
| Field | Type    | Null | Key | Default | Extra          |
+-------+---------+------+-----+---------+----------------+
| id    | int(11) | NO   | PRI | NULL    | auto_increment |
+-------+---------+------+-----+---------+----------------+
1 row in set (0.01 sec)

mysql> desc availability;
+---------------+---------+------+-----+---------+-------+
| Field         | Type    | Null | Key | Default | Extra |
+---------------+---------+------+-----+---------+-------+
| rooms_id      | int(11) | NO   | MUL | NULL    |       |
| occupied_date | date    | NO   |     | NULL    |       |
+---------------+---------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> select * from rooms;
+-----+
| id  |
+-----+
| 123 |
+-----+
1 row in set (0.00 sec)

mysql> select * from availability;
+----------+---------------+
| rooms_id | occupied_date |
+----------+---------------+
|      123 | 2011-05-04    |
+----------+---------------+
1 row in set (0.00 sec)
我的测试数据

mysql> desc rooms;
+-------+---------+------+-----+---------+----------------+
| Field | Type    | Null | Key | Default | Extra          |
+-------+---------+------+-----+---------+----------------+
| id    | int(11) | NO   | PRI | NULL    | auto_increment |
+-------+---------+------+-----+---------+----------------+
1 row in set (0.01 sec)

mysql> desc availability;
+---------------+---------+------+-----+---------+-------+
| Field         | Type    | Null | Key | Default | Extra |
+---------------+---------+------+-----+---------+-------+
| rooms_id      | int(11) | NO   | MUL | NULL    |       |
| occupied_date | date    | NO   |     | NULL    |       |
+---------------+---------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> select * from rooms;
+-----+
| id  |
+-----+
| 123 |
+-----+
1 row in set (0.00 sec)

mysql> select * from availability;
+----------+---------------+
| rooms_id | occupied_date |
+----------+---------------+
|      123 | 2011-05-04    |
+----------+---------------+
1 row in set (0.00 sec)
我的测试查询

mysql> select rooms.* from rooms left outer join availability on rooms.id = availability.rooms_id where rooms.id=123 and availability.occupied_date not between '2011-05-03' and '2011-05-06';
Empty set (0.00 sec)

mysql> select rooms.* from rooms left outer join availability on rooms.id = availability.rooms_id where rooms.id=123 and availability.occupied_date not between '2011-05-05' and '2011-05-06';
+-----+
| id  |
+-----+
| 123 |
+-----+
1 row in set (0.00 sec)
第一个测试查询显示,当房间被占用时,用户在5/3和5/6之间搜索房间123。第二个查询显示,当房间可用时,用户在5/5和5/6之间搜索房间123


这里缺少的成分是左外连接。无论是否存在“表B”(可用性)中的相应记录,该函数都会从“表A”(房间)返回值。您只需要在可用性中不存在可用性的情况,因此为了确保这一点,您应该在结果记录中的可用性中包含一列,并指定一个where子句,该子句要求availability.xxx为NULL。我的测试/示例查询中缺少最后一点,所以请在您这边尝试一下,如果您仍然需要帮助,请告诉我。

听起来很简单,请就房间和可用性进行内部连接。 请忘记“where”类型的隐式联接,而使用显式联接。 通过这种方式,查询更易于阅读,因为您将连接条件和选择条件分开

首先确保您在字段
availability.room\u id
并确保rooms.id是rooms上的主键

select * from rooms where id not in
  (select rooms.id from rooms
   inner join availability on (rooms.id = availability.room_id)
   where availability.date_occupied between StartDate and EndDate)
and rooms.id = 123
如果您想做进一步的测试,您可以添加额外的子句

...Previous query +
  and rooms.smoking = 0
  and rooms.number_of_beds = 2

等等。

我认为最好的方法是简单地运行一个查询,查看房间是否有人占用,如果没有返回行,则指示是否可用

因此,对于您的第一个查询:

SELECT COUNT(id) AS occupied_days FROM availability
WHERE room_id = 123
      AND date_occupied BETWEEN @start_date AND @end_date;
如果
入住天数==0
则房间可用

对于第二个查询,只需将
@end\u date
替换为
date\u ADD(@start\u date,@num\u days)

只是对涉及加入的答案的一些评论:由于您将搜索限制在特定的
房间id
,因此将
可用性
表加入
房间
表是没有意义的,因为它没有提供任何必要的信息。所有这些
LEFT-JOIN
s只会使查询复杂化,可能会降低性能,并且没有任何用处


此外,虽然您可能会对搜索占用率然后推断可用性的方法感到犹豫,但我想,对于查询引擎来说,此查询是迄今为止最快、最容易优化的,因为它基于单个列,如果索引,将使事情变得更快。

SQL 2008解决方案

create table availability
(
room_id int,
date_occupied datetime
)
go

insert into availability values(212,convert(date,DATEADD(d,2,GETDATE())));
insert into availability values(202,convert(date,DATEADD(d,5,GETDATE())));
insert into availability values(209,convert(date,DATEADD(d,7,GETDATE())));
insert into availability values(212,convert(date,DATEADD(d,9,GETDATE())));
insert into availability values(202,convert(date,DATEADD(d,10,GETDATE())));
insert into availability values(202,convert(date,DATEADD(d,20,GETDATE())));
go

CREATE FUNCTION GetMonthTable
(
    @d datetime
) RETURNS @days TABLE
(
    [Date] datetime,
    [Day] varchar(20)
)
BEGIN
    DECLARE @d1 datetime, @d2 datetime, @d3 datetime
    SELECT
    @d1 = DATEADD(mm, DATEDIFF(mm, 0, @d), 0),
    @d2 = DATEADD(dd, -1, DATEADD(mm, DATEDIFF(mm, 0, @d) + 1, 0))

    WHILE @d1 <= @d2
    BEGIN
    INSERT INTO @days SELECT @d1, DATENAME(DW, @d1)
    SELECT @d1 = DATEADD(dd, 1, @d1)
    END
    RETURN
END
go

select A.Date,
       A.Day, 
       convert(bit,isnull((B.date_occupied-B.date_occupied),1))Avalilability 
from        GetMonthTable(getdate()) A
left join   (Select * from availability where room_id=212) B
on A.Date=b.date_occupied
创建表可用性
(
房间号,
日期时间
)
去
插入可用性值(212,convert(date,DATEADD(d,2,GETDATE()));
插入可用性值(202,convert(date,DATEADD(d,5,GETDATE()));
插入可用性值(209,convert(date,DATEADD(d,7,GETDATE())));
插入可用性值(212,convert(date,DATEADD(d,9,GETDATE()));
插入可用性值(202,convert(date,DATEADD(d,10,GETDATE()));
插入可用性值(202,convert(date,DATEADD(d,20,GETDATE()));
去
创建函数getMonhtable
(
@日期时间
)返回@days表
(
[日期]日期时间,
[日]varchar(20)
)
开始
声明@d1日期时间、@d2日期时间、@d3日期时间
挑选
@d1=DATEADD(mm,DATEDIFF(mm,0,@d),0),
@d2=DATEADD(dd,-1,DATEADD(mm,DATEDIFF(mm,0,@d)+1,0))

虽然@d1我也做了类似的事情,但对于给定范围内的所有可用房间。。。我已经修改了你的概念,因为你的房间是一个特定的房间,但这里是原始链接

前提是拥有一个动态创建的“日期范围列表”,而无需实际创建表并显式插入行。这可以通过使用MySQL查询变量来实现。我使用limit命令从(任意)表查询我需要多少个条目。。您的预订桌应该很好。。。然后,我通过在找不到房间的地方创建的特定日期来查询

select  JustDates.OpenDate
    from 
        ( SELECT 
                 @r:= date_add(@r, interval 1 day ) OpenDate
            FROM 
                 (select @r := current_date()) vars,
                availability limit 30 ) JustDates
    where
        JustDates.OpenDate not in
           ( select date_occupied 
                 from availability
                 where availability.room_id = OneYouWant
                   and availability.date_occupied = JustDates.OpenDate )
    order by 
       JustDates.OpenDate
如果你想要房间信息,你可以得到一个笛卡尔连接,因为你已经知道这个房间了,所有的东西都是一样的

select Rooms.*
    from Rooms,
         ( AboveQuery ) OpenDates
    where Rooms.Room_ID = OneYouWant
您可以查看到另一个解决方案的链接,以获得更多关于如何初始化从“current_date()”开始的@r的说明,并且限制30允许它在可用性表的笛卡尔坐标中持续30天。有限的30条记录中的每一条新记录都将继续更新@r到1天以上。因此,在本例中,内部pre获取接下来的30天,然后WHERE NOT in进入特定房间的可用性表,并动态生成符合条件的日期。。。这将只返回尚未占用的日期

希望的
SELECT r.*
FROM rooms r
  LEFT JOIN availability av
    ON av.room_id = r.id
WHERE r.id = 123
  AND av.date_occupied BETWEEN start_date AND end_date
GROUP BY r.id
HAVING count(av.room_id) = 0 
SELECT *
FROM rooms
WHERE id = 123
  AND NOT EXISTS
    ( SELECT 1
      FROM availability
      WHERE date_occupied BETWEEN start_date AND end_date
        AND room_id = 123
    ) 
DATE_ADD( start_date, INTERVAL 2 DAY)
(start_date + INTERVAL 2 DAY)
select datum as available_date
  from calendar c
 where c.datum between date '2011-01-01' and date '2011-01-10'
   and c.datum not in(
        select occupied_date 
          from availability
         where room_id = 1);
select case when count(*) = 3 then 'Yes' else 'Nope' end as available
  from calendar c
 where c.datum between date '2011-01-06' and date '2011-01-06' + interval '2' day
   and c.datum not in(
        select occupied_date 
          from availability
         where room_id = 1);