假设我有一个reservations
表,用于存储有关特定资源何时被保留的信息。
CREATE TABLE reservations (
start_time timestamp not null,
finish_time timestamp not null,
id serial primary key
);
它包含数据:
id start_time finish_time
1 "2014-05-01 09:30:00" "2014-05-01 10:00:00"
2 "2014-05-01 10:15:00" "2014-05-01 11:00:00"
3 "2014-05-01 11:30:00" "2014-05-01 11:45:00"
如果我生成一系列连续时间戳,间隔15分钟,如下:
SELECT timestamp as start_time, (timestamp + '15 minutes') AS finish_time FROM generate_series('2014-05-01 09:00'::timestamp, '2014-05-01 11:45'::timestamp, interval '15 minutes') AS timestamp;
会给我:
start_time finish_time
"2014-05-01 09:00:00" "2014-05-01 09:15:00"
"2014-05-01 09:15:00" "2014-05-01 09:30:00"
"2014-05-01 09:30:00" "2014-05-01 09:45:00"
...
"2014-05-01 11:15:00" "2014-05-01 11:30:00"
"2014-05-01 11:30:00" "2014-05-01 11:45:00"
"2014-05-01 11:45:00" "2014-05-01 12:00:00"
如何找到没有预订的时间间隔?所以我正在寻找的数据是:
start_time finish_time
"2014-05-01 09:00:00" "2014-05-01 09:15:00"
"2014-05-01 09:15:00" "2014-05-01 09:30:00"
"2014-05-01 10:00:00" "2014-05-01 10:15:00"
"2014-05-01 11:00:00" "2014-05-01 11:15:00"
"2014-05-01 11:15:00" "2014-05-01 11:30:00"
"2014-05-01 11:45:00" "2014-05-01 12:00:00"
N.B - 我不必使用generate_series
,但我觉得它看起来很有用!我唯一的要求是找到未预订资源的时间间隔列表。
答案 0 :(得分:2)
我建议将generate_series
与OVERLAPS
运算符结合使用,并对临时表进行一些创造性使用。
我相信这应该可以解决这个问题(需要调整时间段以适应更大的时间范围,并且可能需要对更大的数据集进行一些性能调整):
INSERT INTO reservations (start_time, finish_time)
VALUES ('2014-05-01 09:30:00', '2014-05-01 10:00:00'),
('2014-05-01 10:15:00', '2014-05-01 11:00:00'),
('2014-05-01 11:30:00', '2014-05-01 11:45:00');
CREATE TABLE timeslots AS
SELECT timestamp as start_time, (timestamp + '15 minutes') AS finish_time
FROM generate_series('2014-05-01 09:00'::timestamp,
'2014-05-01 11:45'::timestamp,
interval '15 minutes') AS timestamp;
CREATE TEMP TABLE slots_in_use AS
SELECT DISTINCT t.start_time, t.finish_time
FROM timeslots AS t
JOIN reservations AS r ON ( ((t.start_time, t.finish_time) OVERLAPS (r.start_time, r.finish_time)))
ORDER BY t.start_time, t.finish_time;
CREATE TEMP TABLE free_timeslots AS
SELECT *
FROM timeslots;
DELETE FROM free_timeslots as x
WHERE EXISTS (SELECT 1
FROM slots_in_use AS s
WHERE x.start_time = s.start_time
AND x.finish_time = s.finish_time
);
SELECT *
FROM free_timeslots
ORDER BY start_time, finish_time;
这产生以下结果(11-11:15和11:15-11:30作为2个单独的间隔而不是1,这是15分钟的块将产生的):
START_TIME FINISH_TIME
May, 01 2014 09:00:00+0000 May, 01 2014 09:15:00+0000
May, 01 2014 09:15:00+0000 May, 01 2014 09:30:00+0000
May, 01 2014 10:00:00+0000 May, 01 2014 10:15:00+0000
May, 01 2014 11:00:00+0000 May, 01 2014 11:15:00+0000
May, 01 2014 11:15:00+0000 May, 01 2014 11:30:00+0000
May, 01 2014 11:45:00+0000 May, 01 2014 12:00:00+0000
答案 1 :(得分:1)
SELECT slots.slot_start, slots.slot_end
FROM (
SELECT tick as slot_start, tick + '15 minutes'::interval AS slot_end
FROM generate_series('2014-05-01 09:00'::timestamp
, '2014-05-01 11:45'::timestamp, interval '15 minutes') AS tick
) slots
WHERE NOT EXISTS (
SELECT * FROM reservations rx
WHERE (rx.start_time, rx.finish_time) OVERLAPS (slots.slot_start, slots.slot_end)
)
;