Você pode usar a função generate_series() para mascarar o horário não comercial:
with gaps as (
select
upper(during) as start,
lead(lower(during),1,upper(during)) over (ORDER BY during) - upper(during) as gap
from (
select during
from reservation
union all
select
unnest(case
when pyha is not null then array[tsrange(d, d + interval '1 day')]
when date_part('dow', d) in (0, 6) then array[tsrange(d, d + interval '1 day')]
when d::date = '2012-11-14' then array[tsrange(d, d + interval '9 hours'), tsrange(d + interval '18 hours', d + interval '1 day')]
else array[tsrange(d, d + interval '8 hours'), tsrange(d + interval '18 hours', d + interval '1 day')]
end)
from generate_series(
'2012-11-14'::timestamp without time zone,
'2012-11-14'::timestamp without time zone + interval '2 week',
interval '1 day'
) as s(d)
left join pyha on pyha = d::date
) as x
)
select *
from gaps
where gap > '0'::interval
order by start
Deixe-me explicar algumas partes complicadas:
- você não precisa inserir datas para sab/dom em
pyha
table porque você pode usardate_part('dow', d)
função. Usepyha
mesa apenas para feriados. 'dow' retorna 0 ou 6 para Sun ou Sat, respectivamente. - feriados públicos e sáb/sol podem ser representados como intervalo único (0..24). Os dias da semana devem ser representados por dois intervalos (0..8) e (18..24), portanto, unnest() e array[]
- você pode especificar a data de início e duração na função generate_series()
Com base na sua atualização da pergunta, adicionei outro
when
para case
:when d::date = '2012-11-14' then array[tsrange(d, d + interval '9 hours'), tsrange(d + interval '18 hours', d + interval '1 day')]
A ideia é produzir diferentes intervalos para a data de início (
d::date = '2012-11-14'
):(0..9) e (18..24)