我有一个酒店预订系统的查询,我需要找到特定房间可用的日期。 (这是一家精品酒店,人们预订特定的房间,所以他们在得到这个代码之前就知道了他们想要的确切房间。我所追求的结果是一个房间的细节,我在查询中指定的房间 - - 我不是在寻找多个房间的信息。)
'availability'表架构很简单,每一行都是:
room_id
date_occupied - a single day that is occupied (like '2011-01-01')
因此,例如,如果一个房间从1月1日到1月5日被占用,则可用性表中会添加五行,每天占用一个房间。
这就是我想要解决的问题:
SELECT rooms.* FROM rooms, availability WHERE rooms.id = 123 AND availability.room_id = rooms.id AND nothing between start_date and end_date is in availability.date_occupied
SELECT rooms.* FROM rooms, availability WHERE rooms.id = 123 AND availability.room_id = rooms.id AND start_date, start_date+1day and start_date+2days is not in availability.date_occupied
我有点卡住试图找出确切的联接。有什么建议?请注意,如果它有帮助,我完全可以使用可用性表的不同模式。无论是什么使查询最有效。
答案 0 :(得分:1)
我认为最好的方法是简单地运行查询以查看房间是否被占用,并在没有返回任何行的情况下指示可用性。
因此,首先查询:
SELECT COUNT(id) AS occupied_days FROM availability
WHERE room_id = 123
AND date_occupied BETWEEN @start_date AND @end_date;
如果occupied_days == 0
,则房间可用。
对于第二个查询,只需将@end_date
替换为DATE_ADD(@start_date, @num_days)
对涉及联接的答案的一些评论:由于您将搜索限制为特定的room_id
,因此将availability
表加入room
表是没有意义的,因为它没有提供必要的信息。所有这些LEFT JOIN
只会使查询复杂化,可能会影响性能并且不会提供任何用途。
此外,虽然您可能会厌倦搜索占用率然后推断可用性的方法,但我猜这个查询是查询引擎优化的最快和最简单的,因为它基于单个列,如果编入索引,会使事情变得更快。
答案 1 :(得分:1)
我已经做了类似的事情,但是对于所有房间在给定范围内可用...我已经修改了你的概念,因为你的是一个特定的房间,但是这是原来的链接 Link to other registration
前提是拥有动态创建的“日期范围列表”,而无需实际创建表并显式插入行。这可以通过使用MySQL查询变量来完成。我从一个(任何)表中查询一个限制命令,我需要多少条目...你的预订表应该没问题...然后,我通过创建的特定日期查询,找不到房间。
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的更多说明,并且LIMIT 30允许它因笛卡尔到达而导致30天后退出可用性表。 LIMITed 30记录中的每条新记录将继续将@r更新为1天。所以内部预先在这个例子中预测接下来的30天,那么WHERE NOT IN进入特定房间的可用性表并动态构建合格日期...这只会返回尚未占用的日期。
希望这能为您澄清这项技术。
答案 2 :(得分:0)
(这是我根据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> 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。
这里缺少的成分是LEFT OUTER加入。无论是否存在“表B”(可用性)中的相应记录,这都从“表A”(房间)返回值。您只想要在可用性中不存在的情况,因此为了确保这一点,您应该在结果记录中包含可用性列,并指定要求availability.xxx为NULL的WHERE子句。我的测试/示例查询中缺少最后一点,所以请试一试,如果您仍需要帮助,请告诉我。
答案 3 :(得分:0)
听起来很容易在房间和可用性上进行内部连接。 请忘记'where'类型隐式连接并使用显式连接。 这样,查询更容易阅读,因为您将连接条件和选择条件分开。
首先确保您在字段availability.room_id
上有索引
并确保rooms.id是房间的主要钥匙。
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
等
答案 4 :(得分:0)
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
抱歉格式化。我是这个网站的新手
答案 5 :(得分:0)
查询查找具体的时间 房间开始和之间 结束日期:
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
)
关于第二个问题,只需将end_date
更改为
DATE_ADD( start_date, INTERVAL 2 DAY)
或
(start_date + INTERVAL 2 DAY)
答案 6 :(得分:0)
如果在数据库中保留日历表,则查询很简单。请查看this answer,了解如何创建日期表的最小示例。这个答案的其余部分假定该特定表的存在。
用于查找特定房间在开始日期和结束日期之间何时可用的查询:
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);
该查询将返回指定范围内未占用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);
当指定数据范围内的任何天数都没有被占用时,该查询将返回“是”。数字3
对应于日期范围内的天数(开始日期+2天)。
最终注释/警告:如果您提供不存在的room_id,则上述查询将不起作用。如果您的应用程序构建SQL,这不是问题。