Postgres 从 'bigger' 范围和 return 范围集合中删除 'smaller' 范围
Postgres removing 'smaller' ranges from a 'bigger' range and return a aggregate of ranges
我有一个可以处理双重预订的预订系统。一个人为 tsrange 预订房间,然后可以在该房间预订之上预订约会。我能够使约束正常工作,当然约会的 tsrange 必须包含在保留 tsrange 中。
现在,我需要一个查询 returns 一个 tsranges[] 范围的预订是空闲的,即当时还没有预约,但我不知道该怎么做...好吧,我对如何在 plpgsql 循环约会中实现这个有一个粗略的想法,但我想知道是否有一个更优雅的解决方案,使用普通 SQL,可能使用递归 CTE 或 window函数?
例如,假设我对范围有保留:'[2010-01-01 08:00, 2010-01-01 18:00)'
。
以及该预订的以下预约:'[2010-01-01 08:00, 2010-01-01 09:00)';'[2010-01-01 11:00, 2010-01-01 12:00)';'[2010-01-01 14:00, 2010-01-01 17:00)'
此类函数的输出类似于:'[2010-01-01 09:00, 2010-01-01 11:00)','[2010-01-01 12:00, 2010-01-01 14:00)','[2010-01-01 17:00, 2010-01-01 18:00)'
这是一个示例 dbfiddle,其中包含简化的架构:
create table reservation (
id numeric,
room_id numeric,
during tsrange
);
create table appointment (
id serial,
on_reservation numeric,
during tsrange
);
insert into reservation (id, room_id, during)
VALUES (1, 1, '[2010-01-01 08:00, 2010-01-01 18:00)');
insert into appointment (id, on_reservation, during)
VALUES (2, 1, '[2010-01-01 08:00, 2010-01-01 09:00)');
insert into appointment (id, on_reservation, during)
VALUES (3, 1, '[2010-01-01 10:00, 2010-01-01 12:00)');
insert into appointment (id, on_reservation, during)
VALUES (4, 1, '[2010-01-01 14:00, 2010-01-01 17:00)');
我仍然不熟悉 pg14 中添加的多范围支持,但如果这让事情变得更容易,我可以升级...
使用 PostgreSQL v14 和您的数据模型,这可以像
一样简单
SELECT r.id,
/* convert the reservation to a multirange */
tsmultirange(r.during)
-
/* aggregate the appointments to a multirange */
range_agg(a.during)
AS free_slots
FROM reservation AS r
JOIN appointment AS a ON a.on_reservation = r.id
GROUP BY r.id, r.during;
我有一个可以处理双重预订的预订系统。一个人为 tsrange 预订房间,然后可以在该房间预订之上预订约会。我能够使约束正常工作,当然约会的 tsrange 必须包含在保留 tsrange 中。
现在,我需要一个查询 returns 一个 tsranges[] 范围的预订是空闲的,即当时还没有预约,但我不知道该怎么做...好吧,我对如何在 plpgsql 循环约会中实现这个有一个粗略的想法,但我想知道是否有一个更优雅的解决方案,使用普通 SQL,可能使用递归 CTE 或 window函数?
例如,假设我对范围有保留:'[2010-01-01 08:00, 2010-01-01 18:00)'
。
以及该预订的以下预约:'[2010-01-01 08:00, 2010-01-01 09:00)';'[2010-01-01 11:00, 2010-01-01 12:00)';'[2010-01-01 14:00, 2010-01-01 17:00)'
此类函数的输出类似于:'[2010-01-01 09:00, 2010-01-01 11:00)','[2010-01-01 12:00, 2010-01-01 14:00)','[2010-01-01 17:00, 2010-01-01 18:00)'
这是一个示例 dbfiddle,其中包含简化的架构:
create table reservation (
id numeric,
room_id numeric,
during tsrange
);
create table appointment (
id serial,
on_reservation numeric,
during tsrange
);
insert into reservation (id, room_id, during)
VALUES (1, 1, '[2010-01-01 08:00, 2010-01-01 18:00)');
insert into appointment (id, on_reservation, during)
VALUES (2, 1, '[2010-01-01 08:00, 2010-01-01 09:00)');
insert into appointment (id, on_reservation, during)
VALUES (3, 1, '[2010-01-01 10:00, 2010-01-01 12:00)');
insert into appointment (id, on_reservation, during)
VALUES (4, 1, '[2010-01-01 14:00, 2010-01-01 17:00)');
我仍然不熟悉 pg14 中添加的多范围支持,但如果这让事情变得更容易,我可以升级...
使用 PostgreSQL v14 和您的数据模型,这可以像
一样简单SELECT r.id,
/* convert the reservation to a multirange */
tsmultirange(r.during)
-
/* aggregate the appointments to a multirange */
range_agg(a.during)
AS free_slots
FROM reservation AS r
JOIN appointment AS a ON a.on_reservation = r.id
GROUP BY r.id, r.during;