sql >> Base de Datos >  >> RDS >> PostgreSQL

¿Cómo devolver solo el tiempo de trabajo de las reservas en PostgreSql?

Puede usar la función generate_series() para enmascarar el horario no 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

Déjame explicarte algunas partes difíciles:

  • no tienes que insertar fechas para sábado/domingo en pyha tabla porque puede usar date_part('dow', d) función. Usa pyha mesa solo para festivos. 'dow' devuelve 0 o 6 para dom o sáb respectivamente.
  • los días festivos y el sábado/domingo se pueden representar como un solo intervalo (0..24). Los días de la semana deben representarse mediante dos intervalos (0..8) y (18..24), por lo tanto, unnest() y array[]
  • puede especificar la fecha de inicio y la duración en la función generate_series()

Según su actualización de la pregunta, agregué otro when al case :

when d::date = '2012-11-14' then array[tsrange(d, d + interval '9 hours'), tsrange(d + interval '18 hours', d + interval '1 day')]

La idea es producir diferentes intervalos para la fecha de inicio (d::date = '2012-11-14' ):(0..9) y (18..24)