Следующее использует большинство методов, упомянутых @Brits. Они предоставляют очень хорошую информацию, поэтому я не буду повторяться, но предлагаю вам просмотреть ее (и ссылки). Однако я придерживаюсь немного другого подхода. Сначала пара таблиц меняется. Я использую день ISO недели 1-7 (понедельник-воскресенье), а не название дня. Название дня легко вывести на свидание позже. Также я использую интервал вместо времени для времени начала и окончания. (Тип данных времени работает для большинства сценариев ios, но есть и другой (подробнее позже). Одна вещь, которую ваше описание не проясняет, это то, включено ли время окончания в доступное время или нет. Если включен последний интервал будет 11: 00-11: 15. Если исключен, последний интервал 10: 45-11: 00. Я предполагал исключить это. В окончательных результатах время окончания следует понимать как «до, но не включая».
-- setup
create table availabilities (weekday integer, start_time interval, end_time interval);
insert into availabilities (weekday , start_time , end_time )
select wkday
, start_time
, end_time
from (select *
from (values (1, '09:00'::interval, '11:00'::interval)
, (1, '13:00'::interval, '17:00'::interval)
, (2, '08:00'::interval, '17:00'::interval)
, (3, '08:30'::interval, '10:45'::interval)
, (4, '10:30'::interval, '12:45'::interval)
) as v(wkday,start_time,end_time)
) r ;
select * from availabilities;
Запрос Он начинается с CTE (next_week), генерирует запись для каждого дня недели, начинающегося с понедельника, и соответствующий номер дня ISO для него. Основной запрос объединяет их с таблицей доступности, чтобы выбрать время для соответствующих дней. Наконец, этот результат перекрестно соединяется с сгенерированной временной меткой, чтобы получить 15-минутные интервалы.
-- Main
with next_week (wkday,tm) as
(SELECT n+1, date_trunc('week', current_date) + interval '1 week' + n*interval '1 day'
from generate_series (0, 6) n
)
select to_char(gdtm,'Day'), gdtm start_time, gdtm+interval '15 min' end_time
from ( select wkday, tm, start_time, end_time
from next_week nw
join availabilities av
on (av.weekday = nw.wkday)
) s
cross join lateral
generate_series(start_time+tm, end_time+tm- interval '1 sec', interval '15 min') gdtm ;
Пропадание Как уже упоминалось, есть один сценарий, когда тип данных времени не работает удовлетворительно, но вам может и не понадобиться. Что происходит, когда сменный работник говорит, что у них есть свободное время 23: 00-01: 30. Поверьте мне, когда сменный работник идет на работу в 22:00 пятницы, 01:30 по-прежнему в пятницу вечером, хотя календарь может не согласиться. (Я работал над этим сдвигом в течение многих лет.) Следующее использование интервальных обработчиков этой проблемы. Загрузка тех же данных, что и ранее, с добавлением для этого случая.
insert into availabilities (weekday, start_time, end_time )
select wkday
, start_time
, end_time + case when end_time < start_time
then interval '1 day'
else interval '0 day'
end
from (select *
from (values (1, '09:00'::interval, '11:00'::interval)
, (1, '13:00'::interval, '17:00'::interval)
, (2, '08:00'::interval, '17:00'::interval)
, (3, '08:30'::interval, '10:45'::interval)
, (5, '23:30'::interval, '02:30'::interval) -- Friday Night - Saturday Morning
) as v(wkday,start_time,end_time)
) r
;
select * from availabilities;
Надеюсь, это поможет.