PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Comment renvoyer uniquement le temps de travail des réservations dans PostgreSql ?

Vous pouvez utiliser la fonction generate_series() pour masquer les heures non ouvrables :

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

Laissez-moi vous expliquer quelques parties délicates :

  • vous n'avez pas besoin d'insérer les dates de samedi/dimanche dans pyha table car vous pouvez utiliser date_part('dow', d) une fonction. Utilisez pyha table uniquement pour les jours fériés. 'dow' renvoie 0 ou 6 pour Sun ou Sam respectivement.
  • les jours fériés et sam/dim peuvent être représentés comme un seul intervalle (0..24). Les jours de la semaine doivent être représentés par deux intervalles (0..8) et (18..24) d'où unnest() et array[]
  • vous pouvez spécifier la date de début et la longueur dans la fonction generate_series()

Sur la base de votre mise à jour de la question, j'ai ajouté un autre when à case :

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

L'idée est de produire différents intervalles pour la date de début (d::date = '2012-11-14' ):(0..9) et (18..24)