复杂 SQL 查询建议:预留分配逻辑
我正在尝试在 SQL Server 2008 上执行一个复杂的查询(至少对我来说很复杂),到目前为止我可以做到这一点。这是代码;
DECLARE @Hotels AS TABLE(
HotelID INT,
HotelName NVARCHAR(100)
);
DECLARE @HotelAllotments AS TABLE(
HotelID INT,
StartDate DATETIME,
EndDate DATETIME,
Allotment INT
);
DECLARE @Reservations AS TABLE(
ReservationID INT,
HotelID INT,
CheckIn DATETIME,
CheckOut DATETIME,
IsCanceled BIT
);
INSERT @Hotels VALUES(1,'Foo Hotel');
INSERT @Hotels VALUES(2,'Poo Hotel');
INSERT @HotelAllotments VALUES(1,'2011-01-01', '2011-02-01', 10);
INSERT @HotelAllotments VALUES(1,'2011-02-02', '2011-02-18', 7);
INSERT @HotelAllotments VALUES(1,'2011-02-19', '2011-05-18', 19);
INSERT @HotelAllotments VALUES(1,'2011-05-19', '2011-10-18', 30);
INSERT @HotelAllotments VALUES(2,'2011-05-19', '2011-10-18', 30);
INSERT @Reservations VALUES(100, 1, '2011-05-10','2011-05-24',0);
INSERT @Reservations VALUES(101, 1, '2011-05-18','2011-05-28',0);
INSERT @Reservations VALUES(102, 1, '2011-03-07','2011-03-19',0);
INSERT @Reservations VALUES(103, 1, '2011-08-29','2011-09-07',0);
INSERT @Reservations VALUES(104, 1, '2011-09-01','2011-09-07',1);
INSERT @Reservations VALUES(105, 1, '2011-09-01','2011-09-07',1);
with e as(
SELECT ReservationID as resid1, CheckIn as chin1, 1 as lvl
FROM @Reservations res1
WHERE res1.HotelID = 1
UNION ALL
SELECT ReservationID as resid2, DATEADD(DAY,1,stall.chin1) as chin2, 1
FROM @Reservations res2
INNER JOIN e stall ON stall.chin1 < res2.CheckOut
WHERE stall.resid1 = res2.ReservationID
)
SELECT tb.chin1, SUM(lvl)
FROM e tb
GROUP BY tb.chin1
ORDER BY tb.chin1 DESC
在@HotelAllotments部分,您可以看到开始和结束日期。分配是按日计算的。我的意思是如果行如下所示;
INSERT @HotelAllotments VALUES(1,'2011-01-01', '2011-01-03', 10);
意思是这个;
- id 为 1 的酒店在 2011-01-01 拥有 10 个配额
- id 为 1 的酒店在 2011-01-02 拥有 10 个配额
- id 为 1 的酒店在 2011-01-03 拥有 10 个配额
然后,如果我们收到 2011-01-01 至 2011-01-03 之间的预订,例如 以下;
INSERT @Reservations VALUES(106, 1, '2011-01-01','2011-01-03',0);
情况如下;
- id 为 1 的酒店在 2011-01-01 预订后还剩 9 个房
- 位 id 为 1 的酒店在 2011-01-02 预订后还剩 9 个房
- 位 id 为 1 的酒店有 10 2011-01-03 预订后剩余分配
上面,我创建了一些临时表并插入了一些假值,然后我尝试查询。它让我到达某个地方(我不知道如何称呼它。所以如果你有一个 有机会运行查询,您会看到到目前为止它已经到达了我的位置),但不是我需要的地方。我在这里需要的是;
我需要列出酒店签订协议的所有日期以及收到预订后剩余的分配额。这是一个例子;
HotelID Date Allotment
------- ---------- ---------
1 2011-01-01 9
1 2011-01-02 9
1 2011-01-03 10
1 2011-01-04 10
1 2011-01-05 10
那么我怎样才能实现这一目标呢?
编辑
有些人应该想知道为什么预订的前两天的分配被取消,但最后两天却没有。这是因为最后一天客人不会在酒店呆一整天。她/他应该清空房间直到中午 12:00。因此最后日期不会有任何分配使用。
I am trying to do a complex query (at least, it is complex for me) on SQL Server 2008 and so far I can come this far. Here is the code;
DECLARE @Hotels AS TABLE(
HotelID INT,
HotelName NVARCHAR(100)
);
DECLARE @HotelAllotments AS TABLE(
HotelID INT,
StartDate DATETIME,
EndDate DATETIME,
Allotment INT
);
DECLARE @Reservations AS TABLE(
ReservationID INT,
HotelID INT,
CheckIn DATETIME,
CheckOut DATETIME,
IsCanceled BIT
);
INSERT @Hotels VALUES(1,'Foo Hotel');
INSERT @Hotels VALUES(2,'Poo Hotel');
INSERT @HotelAllotments VALUES(1,'2011-01-01', '2011-02-01', 10);
INSERT @HotelAllotments VALUES(1,'2011-02-02', '2011-02-18', 7);
INSERT @HotelAllotments VALUES(1,'2011-02-19', '2011-05-18', 19);
INSERT @HotelAllotments VALUES(1,'2011-05-19', '2011-10-18', 30);
INSERT @HotelAllotments VALUES(2,'2011-05-19', '2011-10-18', 30);
INSERT @Reservations VALUES(100, 1, '2011-05-10','2011-05-24',0);
INSERT @Reservations VALUES(101, 1, '2011-05-18','2011-05-28',0);
INSERT @Reservations VALUES(102, 1, '2011-03-07','2011-03-19',0);
INSERT @Reservations VALUES(103, 1, '2011-08-29','2011-09-07',0);
INSERT @Reservations VALUES(104, 1, '2011-09-01','2011-09-07',1);
INSERT @Reservations VALUES(105, 1, '2011-09-01','2011-09-07',1);
with e as(
SELECT ReservationID as resid1, CheckIn as chin1, 1 as lvl
FROM @Reservations res1
WHERE res1.HotelID = 1
UNION ALL
SELECT ReservationID as resid2, DATEADD(DAY,1,stall.chin1) as chin2, 1
FROM @Reservations res2
INNER JOIN e stall ON stall.chin1 < res2.CheckOut
WHERE stall.resid1 = res2.ReservationID
)
SELECT tb.chin1, SUM(lvl)
FROM e tb
GROUP BY tb.chin1
ORDER BY tb.chin1 DESC
On @HotelAllotments section, there are start and end dates as you can see. The allotment is for daily basis. I mean if row is like below;
INSERT @HotelAllotments VALUES(1,'2011-01-01', '2011-01-03', 10);
It means this;
- The Hotel whose id is 1 has 10 allotment on 2011-01-01
- The Hotel whose id is 1 has 10 allotment on 2011-01-02
- The Hotel whose id is 1 has 10 allotment on 2011-01-03
Then, after that if we receive a reservation between 2011-01-01 and 2011-01-03, like below;
INSERT @Reservations VALUES(106, 1, '2011-01-01','2011-01-03',0);
The situation will be as below;
- The Hotel whose id is 1 has 9 allotment left after the reservation on 2011-01-01
- The Hotel whose id is 1 has 9 allotment left after the reservation on 2011-01-02
- The Hotel whose id is 1 has 10 allotment left after the reservation on 2011-01-03
Above, I have created some temp tables and inserted some fake values and I tried a query. It gets me somewhere (I don't know how to call it. So if you have a
chance to run the query, you would see where it has gotten me so far) but not the place I need. What I need here is that;
I need to list all the dates which a hotel has an agreement and its left allotments after received reservations. here is an example;
HotelID Date Allotment
------- ---------- ---------
1 2011-01-01 9
1 2011-01-02 9
1 2011-01-03 10
1 2011-01-04 10
1 2011-01-05 10
So how can I achieve this?
EDIT
Some them should wonder why an allotment is taken away for the first two days of the reservation, but not the last one. It is because the guest wouldn't be staying all day at the hotel at the last day. S/he should empty the room until 12:00 am. So there won't be any allotment usage on the last date.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
此解决方案使用系统表
master..spt_values
,作为<一href="http://www.sqlservercentral.com/articles/T-SQL/62867/" rel="nofollow noreferrer" title="“Numbers”或“Tally”表:它是什么以及它如何替换一个循环。">统计表来获取日期列表而不是日期范围。接下来,扩展的分配列表与@Resevations 表连接。对于列表中的每个日期,相应的分配都会减少范围与给定日期匹配的预订数量。This solution uses a system table,
master..spt_values
, as a tally table to obtain the lists of dates instead of the date ranges. Next, the expanded allotment list is joined with the @Resevations table. For every date in the list, the correpsonding allotment is decreased by the number of reservations whose ranges match the given date.我写 where 子句有点仓促。不知道你是否想整理一下空白的日子。这是我在设置 where 子句后想到的。我使用 datejumps 的原因是为了补偿 sql 中 100 次重复调用的限制。因此,我加入系统表中的 10 行,更好地利用 100 递归,这样我可以获得 1000 行而不是 100 行。
I was a bit hasty on writing my where clause. I didnt know if you wanted to sort out the blank days. here is what i came up with after setting the where clause. The reason i have the datejumps is to compensate for the limitation of 100 recusive calls in sql. So I join with 10 rows from a system table make better use of the 100 recusive, that way i can get 1000 rows instead of 100.