SQL中的岛屿与间隙(一天中的时间点)
我们正在努力让在工作中预订外出用车这件事变得更容易一些。如今我们按1小时的时段来创建,但如果有人想把其中一个时段用整整一天,他们需要多次重复预订流程。
我想要做的是创建一个车辆可用的时段,并允许人们按任意时长来选择并预订这辆车。
基于这个想法,我想要一些SQL来识别车辆尚未被预订的时段,以便把这些“可用时段”呈现给想要用车的用户。
我的会话会有一个from和 to日期,预订也会有相同的字段。我之前试着理解这个“岛屿场景”,但在这里有点吃力。
DECLARE @BookingSession TABLE
(
id_BookingSession INT
,SessionStart DATETIME
,SessionEnd DATETIME
);
INSERT INTO @BookingSession (id_BookingSession,SessionStart,SessionEnd)
VALUES
(
1,'20260507 09:00','20260507 17:00'
);
DECLARE @Bookings TABLE
(
id_BookingSession INT
,id_BookingSession_Slot INT
,TimeFrom DATETIME
,TimeUntil DATETIME
);
--Make some bookings:
INSERT INTO @Bookings (id_BookingSession,id_BookingSession_Slot,TimeFrom,TimeUntil)
VALUES
(1,90,'20260507 10:05','20260507 10:45') -- 40 Min booking
,(1,91,'20260507 11:05','20260507 11:30') -- 25 Min booking
,(1,93,'20260507 11:30','20260507 12:30') -- 60 Min booking (So no gap before last one);
SELECT * FROM @BookingSession;
SELECT * FROM @bookings;
在这种场景下,我希望得到如下输出:
| Result |
|---|
| 09:00 - 10:05 Available |
| 10:45 - 11:05 Available |
| 12:30 - 17:00 Available |
解决方案
我只需要把行合并在一起并使用LEAD() 来找出下一行的开始时间。
(一个间隙从当前EndTime开始,到下一行的StartTime结束。)
然后还要把预订会话的那一行也各包含两次,一次作为第一个间隙的起始,一次作为最后一个间隙的结束。
最后排除所有Start不小于End的结果。
注:此处假设预订不能重叠。
WITH
combined AS
(
SELECT
id_BookingSession
,TimeFrom
,TimeUntil
FROM
Bookings
UNION ALL
SELECT
id_BookingSession
,NULL
,SessionStart
FROM
BookingSession
UNION ALL
SELECT
id_BookingSession
,SessionEnd
,NULL
FROM
BookingSession
),
gaps AS
(
SELECT
id_BookingSession,
TimeUntil AS TimeFrom,
LEAD(TimeFrom) OVER (
PARTITION BY id_BookingSession
ORDER BY TimeFrom
)
AS TimeUntil
FROM
combined
)
SELECT
*
FROM
gaps
WHERE
TimeFrom < TimeUntil
ORDER BY
1,2,3
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。