我有一个看起来像这样的数据库: https://i.imgur.com/dwaqUF2.png
我想选择在给定时间段内没有任何预订的所有房间。
这是我尝试过的:
SELECT idRoom, type, beds FROM Room r
INNER JOIN Reservation_has_Room has on r.idRoom = has.Room_idRoom
INNER JOIN Rezervation re on has.Reservation_has_Room = re.idReservation
WHERE (re.checkIn<'2019-06-04'
AND re.checkOut<'2019-06-01')
or
(re.checkIn>'2019-06-04'
AND re.CheckOut>'2019-06-01');
但是此脚本每次找到不与日期重叠的预订都返回一个房间。
我认为我可能会被误解。 就是这种情况: 在房间中,我有以下记录:
idRoom, type, beds
'1', 'Standard', '1'
'2', 'Standard', '1'
idReservation, checkIn, checkOut
'1', '2019-05-22', '2019-06-03'
'2', '2021-05-22', '2021-06-03'
'3', '2022-05-22', '2022-06-03'
Reservation_idReservation, Room_idRoom
'1', '1'
'2', '1'
'3', '1'
因此,如您所见,房间nr 1我有3个预订。一个是重叠的,其余不是。在这种情况下,@ AlexYes中的脚本返回以下内容:
idRoom, type, beds
'1', 'Standard', '1'
'1', 'Standard', '1'
'2', 'Standard', '1'
因此它返回一号房间,甚至两次。 我的预期结果是:
idRoom, type, beds
'2', 'Standard', '1'
所以只有2号房可用。
答案 0 :(得分:1)
这是重叠范围问题,您的WHERE
子句应为:
WHERE
re.checkIn <= '2019-06-04' AND
re.checkOut >= '2019-06-01'
您的完整查询:
SELECT
idRoom,
type,
beds
FROM Room r
INNER JOIN Reservation_has_Room has
ON r.idRoom = has.Room_idRoom
INNER JOIN Rezervation re
ON has.Reservation_has_Room = re.idReservation
WHERE
re.checkIn <= '2019-06-04' AND
re.checkOut >= '2019-06-01';
答案 1 :(得分:1)
是的,这样做是因为您正在执行内部联接并过滤保留。您需要的是按时间段条件保留剩余房间的房间,然后过滤没有加入任何房间的单元:
SELECT idRoom, type, beds
FROM Room r
LEFT JOIN ( -- subquery that returns reservation business entities filtered by your time period
SELECT *
FROM Reservation_has_Room has
JOIN Rezervation re
ON has.Reservation_has_Room = re.idReservation
WHERE (re.checkIn <= '2019-06-01' AND re.checkOut >= '2019-06-04') -- (1)
OR re.checkIn between '2019-06-01' and '2019-06-04' -- (2)
OR re.checkOut between '2019-06-01' and '2019-06-04' -- (3)
) rr
ON r.idRoom = rr.Room_idRoom
WHERE rr.checkIn is null -- filter out units that don't have matching reservations
首先按以下3种情况过滤预订:
1)完全重叠的保留 2)预定开始于周期的中间,然后在预定时间结束 3)在预定时间之前开始并在周期中间某处结束的预订
蒂姆建议的情况也可能有效。但主要要点是在联接条件下使用范围过滤器切换到LEFT JOIN
,并使WHERE re.checkIn is null
要使解决方案更具动态性,可以使用子查询仅指定一次时间范围,然后在过滤器中重复使用这些值:
WITH
start_date as (select '2019-06-01'::date)
,end_date as (select '2019-06-04'::date)
并将其作为加入条件:
(
re.checkIn <= (select * from start_date) AND re.checkOut >= (select * from end_date) -- (1)
or re.checkIn between (select * from start_date) and (select * from end_date) -- (2)
or re.checkOut between (select * from start_date) and (select * from end_date) -- (3)
)
答案 2 :(得分:1)
我很确定您这里只需要2张桌子。房间属性和预订属性。如果房间在预订表中,则显然有预订。所以:
room_id start_date end_date
1 s_d1 e_d1
1 s_d2 e_d2
2 s_d3 e_d3
您要查找尚未预订的客户日期范围内的room_id。 (通常到下午12点)
cust_s_d不在s_d和e_d之间,或 cust_e_d不在s_d和e_d之间
select room_id from reservations
where
cust_s_d NOT BETWEEN s_d and e_d
AND
cust_e_d NOT BETWEEN s_d and e_d;
将结果与房间的属性结合在一起,就是这样。
答案 3 :(得分:1)
我会使用not exists
:
SELECT r.*
FROM Room r
WHERE NOT EXISTS (SELECT 1
FROM Reservation_has_Room rhr INNER JOIN
Rezervation re
ON rhr.Reservation_has_Room = re.idReservation
WHERE r.idRoom = rhr.Room_idRoom AND
re.checkIn <= '2019-06-04' AND
re.checkOut >= '2019-06-01'
);
重叠的逻辑很简单,如果某人在最后一个日期之前或之后入住,而在第一天或第一天之后退房,则存在重叠并且房间不可用。 / p>
这说明了间隔可能重叠的所有可能方式。请注意,这包括全部四天;您可能会或可能不希望包括第一天和最后几天,具体取决于您的入住/退房规则。