我有一项任务,我正在使用一个虚构的酒店数据库。我正在尝试写一个查询“查找为同一日期预订了两个房间的客人的预订”。
我有一个列出来宾的guest
表。客人可以预订0次或以上
hotel7=# SELECT * FROM guest;
guest_id | name | phone | email
----------+---------+--------------+---------------
1 | kat | 111-111-1111 | kat@g.com
2 | andy | 222-222-2222 | andy@g.com
3 | theda | 333-333-3333 | theda@g.com
4 | forrest | 444-444-4444 | forrest@g.com
5 | trent | 555-555-5555 | trent@g.com
6 | cyle | 666-666-6666 | cyle@g.com
(6 rows)
我有一张列出所有预订的reservation
表格。每个预订有一位客人,可以与一个或多个房间相关联。
hotel7=# SELECT * FROM reservation;
res_id | guest_id | check_in | check_out
--------+----------+------------+------------
1 | 1 | 2017-12-01 | 2017-12-03
2 | 1 | 2017-12-05 | 2017-12-07
3 | 2 | 2017-12-01 | 2017-12-02
4 | 2 | 2017-12-01 | 2017-12-10
5 | 3 | 2017-12-01 | 2017-12-10
6 | 4 | 2017-12-15 | 2017-12-30
7 | 5 | 2017-12-15 | 2017-12-22
(7 rows)
一张room_res
表,显示哪些房间属于哪些预订
hotel7=# SELECT * FROM room_res;
res_id | room_id
--------+---------
1 | 1
1 | 2
2 | 1
3 | 3
3 | 4
4 | 5
5 | 6
6 | 1
7 | 3
(9 rows)
这个命令让我很接近,但我只想向预订2个或更多房间的人展示。
hotel7=# SELECT g.name, r.res_id, r.check_in, r.check_out, rr.room_id
FROM guest AS g
INNER JOIN reservation AS r
ON r.guest_id = g.guest_id
INNER JOIN room_res AS rr
ON rr.res_id = r.res_id;
name | res_id | check_in | check_out | room_id
---------+--------+------------+------------+---------
kat | 1 | 2017-12-01 | 2017-12-03 | 1
kat | 1 | 2017-12-01 | 2017-12-03 | 2
kat | 2 | 2017-12-05 | 2017-12-07 | 1
andy | 3 | 2017-12-01 | 2017-12-02 | 3
andy | 3 | 2017-12-01 | 2017-12-02 | 4
andy | 4 | 2017-12-01 | 2017-12-10 | 5
theda | 5 | 2017-12-01 | 2017-12-10 | 6
forrest | 6 | 2017-12-15 | 2017-12-30 | 1
trent | 7 | 2017-12-15 | 2017-12-22 | 3
(9 rows)
所以我尝试了这个并且空了
hotel7=# SELECT g.name, r.res_id, r.check_in, r.check_out, rr.room_id
FROM guest AS g
INNER JOIN reservation AS r
ON r.guest_id = g.guest_id
INNER JOIN room_res AS rr
ON rr.res_id = r.res_id GROUP BY g.name, r.res_id, r.check_in, r.check_out,
rr.room_id
HAVING COUNT (rr.room_id)>1;
name | res_id | check_in | check_out | room_id
------+--------+----------+-----------+---------
(0 rows)
答案 0 :(得分:1)
只需从rr.room_id
和GROUP BY
列表中删除SELECT
。
SELECT g.name, r.res_id, r.check_in, r.check_out
FROM guest AS g
INNER JOIN reservation AS r ON r.guest_id = g.guest_id
INNER JOIN room_res AS rr ON rr.res_id = r.res_id
GROUP BY g.name, r.res_id, r.check_in, r.check_out
HAVING COUNT (rr.room_id)>1;
当您在房间内分组时,您也将每个组的潜在大小限制为一个房间,并且您将永远无法拥有COUNT(room_id)> 1。
但是,这是问题的简单版本。它只适用于您可以准确地假设预订日期排队,并且如果您松散地阅读问题陈述。如果您需要允许check_in / check_out日期不多的预订,事情会变得复杂得多。以下是我处理的方法:
Reservation
表加入生成的数字表,其中数字值小于DATEDIFF()
和check_in
之间的check_out
check_in
和check_out
列。此外,问题陈述会要求您为在同一天预订两间客房的客人预订。该声明 NOT 仅限于多个房间预订;如果客人符合此条件的任何预订,则严格阅读该问题会为客人找到所有预订。
考虑到这一点,并假设您已有Numbers表,完整查询将如下所示:
WITH EligibleGuests As (
SELECT r.guest_id
FROM reservation r
INNER JOIN Numbers n ON n.Number < DATEDIFF(d, r.check_in, r.check_out)
INNER JOIN room_res AS rr ON rr.res_id = r.res_id
GROUP BY r.guest_id, DATEADD(d, r.check_in, n.Number)
HAVING COUNT (rr.room_id)>1
)
SELECT g.name, r.check_in, r.check_out, rr.room_id
FROM Guests g
INNER JOIN EligibleGuests eg on eg.guest_id = g.guest_id
INNER JOIN Reservations r ON r.guest_id = g.guest_ID
INNER JOIN Room_Res rr on rr.res_id = r.res_id
答案 1 :(得分:0)
我认为这归结为伪装的重叠范围问题。我们可以尝试自我加入reservation
表来检查重叠的预订范围,从而产生两个或更多预留房间。
WITH cte AS (
SELECT DISTINCT r1.guest_id
FROM reservation r1
INNER JOIN room_res rr1
ON r1.res_id = rr1.res_id
INNER JOIN reservation r2
ON r1.check_in < r2.check_out AND
r1.check_out > r2.check_in AND
r1.guest_id = r2.guest_id AND
r1.res_id < r2.res_id
INNER JOIN room_res rr2
ON r2.res_id = rr2.res_id
WHERE
rr1.room_id <> rr2.room_id
)
SELECT g.*
FROM guest g
INNER JOIN cte t
ON g.guest_id = t.guest_id;