Как стать автором
Обновить
0
0
Михаил Ахр @Megacinder

Разработчик баз данных

Отправить сообщение
❌ Ожидание: став сеньором, я буду руководить крупными проектами, иметь большое влияние и говорить другим, что делать!
✅ Реальность: я скучаю по тем временам, когда мне говорили, что делать.

Забавляют синьоры, ноющие, что у них слишком много ответственности. А что мешает уйти на менее ответственную должность? Если ответ "деньги", то это неправильный ответ.

У меня в расчёте SLA учитываются и обеды, и сокращённые пятницы, и сокращённые предпраздничные дни, и по разным типам (запрос или инцидент) эти условия разные.
В общем, этот запрос — это мой стандартный, не самый сложный, рабочий день

Работу в выходные учёл. Можно ещё и обеды учесть, если надо


Заголовок спойлера
with wt_periods(id, start_time, stop_time) as 
    (
        values  (1, '2019-03-29 07:00:00'::timestamp, '2019-04-08 14:00:00'::timestamp)
              , (2, '2019-04-10 07:00:00'::timestamp, '2019-04-10 20:00:00'::timestamp)
              , (3, '2019-04-11 12:00:00'::timestamp, '2019-04-12 16:07:12'::timestamp)
              , (4, '2018-12-28 12:00:00'::timestamp, '2019-01-16 16:00:00'::timestamp)
    )

    ,wt_holyday(id, day_off, comment) as
    (
        values  (79,  '2018-01-01 00:00:00' :: timestamp, 'НГ')
              , (80,  '2018-01-02 00:00:00' :: timestamp, 'НГ')
              , (81,  '2018-01-03 00:00:00' :: timestamp, 'НГ')
              , (82,  '2018-01-04 00:00:00' :: timestamp, 'НГ')
              , (83,  '2018-01-05 00:00:00' :: timestamp, 'НГ')
              , (84,  '2018-01-08 00:00:00' :: timestamp, 'НГ')
              , (85,  '2018-02-23 00:00:00' :: timestamp, 'ДЗО')
              , (86,  '2018-03-08 00:00:00' :: timestamp, 'МЖД')
              , (87,  '2018-03-09 00:00:00' :: timestamp, 'МЖД')
              , (88,  '2018-04-30 00:00:00' :: timestamp, 'Первомай')
              , (89,  '2018-05-01 00:00:00' :: timestamp, 'Первомай')
              , (90,  '2018-05-02 00:00:00' :: timestamp, 'Первомай')
              , (91,  '2018-05-09 00:00:00' :: timestamp, 'День Победы')
              , (92,  '2018-06-11 00:00:00' :: timestamp, 'День России')
              , (93,  '2018-06-12 00:00:00' :: timestamp, 'День России')
              , (94,  '2018-11-05 00:00:00' :: timestamp, 'День народного единства')
              , (95,  '2018-12-31 00:00:00' :: timestamp, 'НГ')
              , (96,  '2019-01-01 00:00:00' :: timestamp, 'НГ')
              , (97,  '2019-01-02 00:00:00' :: timestamp, 'НГ')
              , (98,  '2019-01-03 00:00:00' :: timestamp, 'НГ')
              , (99,  '2019-01-04 00:00:00' :: timestamp, 'НГ')
              , (100, '2019-01-07 00:00:00' :: timestamp, 'НГ')
              , (101, '2019-01-08 00:00:00' :: timestamp, 'НГ')
              , (102, '2019-03-08 00:00:00' :: timestamp, 'МЖД')
              , (103, '2019-05-01 00:00:00' :: timestamp, 'Первомай')
              , (104, '2019-05-02 00:00:00' :: timestamp, 'Первомай')
              , (105, '2019-05-03 00:00:00' :: timestamp, 'Первомай')
              , (106, '2019-05-09 00:00:00' :: timestamp, 'День Победы')
              , (107, '2019-05-10 00:00:00' :: timestamp, 'День Победы')
              , (108, '2019-06-12 00:00:00' :: timestamp, 'День России')
              , (109, '2019-11-04 00:00:00' :: timestamp, 'День народного единства')
    )

    ,wt_slave_holyday(id, day_on, comment) as
    (
        values  (201,  '2018-04-28 00:00:00' :: timestamp, 'Из-за первомая')
              , (202,  '2018-06-09 00:00:00' :: timestamp, 'Из-за дня России')
              , (203,  '2018-12-29 00:00:00' :: timestamp, 'Из-за НГ')
    )

    ,wt_par as
    (
        select
             id
            ,start_time :: timestamp  as i_from_dt
            ,stop_time  :: timestamp  as i_to_dt
            ,10 :: numeric  as i_start_slave_time
            ,19 :: numeric  as i_stop_slave_time
        from
            wt_periods
    )

    ,wt_gen_dt as
    (
        select
             pa1.id
            ,pa1.i_from_dt
            ,pa1.i_to_dt
            ,pa1.i_start_slave_time
            ,pa1.i_stop_slave_time
            ,dt 
            ,case
                 when sh1.day_on is not null
                     then
                         1
                 when sh1.day_on is null
                  and (
                            extract(dow from dt) in (6, 0)
                        or  h1.day_off is not null
                      )
                     then
                         0
                     else
                         1
             end  as is_slave_day
        from wt_par  pa1
            cross join generate_series(
                                        date_trunc('day', pa1.i_from_dt)
                                      , date_trunc('day', pa1.i_to_dt)
                                      , '24 hours' :: interval
                                      )  as dt
            left join wt_holyday  h1 --табличка с праздничными днями
                on h1.day_off = dt

            left join wt_slave_holyday  sh1
                on sh1.day_on = dt
    )

select
     id
    ,i_from_dt
    ,i_to_dt
    ,sum( case --дата конца раб дня 
              when is_slave_day = 0
                  then
                      dt + interval '0 hours'
                  else
                      greatest(
                                least(
                                       dt + interval '1 hours' * i_stop_slave_time
                                     , i_to_dt
                                     )
                              , dt + interval '1 hours' * i_start_slave_time
                              , i_from_dt
                              )
          end
          -
          case --дата начала раб дня 
              when is_slave_day = 0
                  then
                      dt + interval '0 hours'
                  else
                      greatest(
                                dt + interval '1 hours' * i_start_slave_time
                              , i_from_dt
                              )
          end )  as slave_time_mi
from
    wt_gen_dt
group by
     id
    ,i_from_dt
    ,i_to_dt

Ещё и формат поехал. Переписал. Но, думаю, это решение довольно популярно


Заголовок спойлера
with wt_periods(id, start_time, stop_time) as 
    (
        values  (1, '2019-03-29 07:00:00'::timestamp, '2019-04-08 14:00:00'::timestamp)
              , (2, '2019-04-10 07:00:00'::timestamp, '2019-04-10 20:00:00'::timestamp)
              , (3, '2019-04-11 12:00:00'::timestamp, '2019-04-12 16:07:12'::timestamp)
              , (4, '2018-12-28 12:00:00'::timestamp, '2019-01-16 16:00:00'::timestamp)
    )

    ,wt_holyday(id, day_off, comment) as
    (
        values  (79,  '2018-01-01 00:00:00' :: timestamp, 'НГ')
              , (80,  '2018-01-02 00:00:00' :: timestamp, 'НГ')
              , (81,  '2018-01-03 00:00:00' :: timestamp, 'НГ')
              , (82,  '2018-01-04 00:00:00' :: timestamp, 'НГ')
              , (83,  '2018-01-05 00:00:00' :: timestamp, 'НГ')
              , (84,  '2018-01-08 00:00:00' :: timestamp, 'НГ')
              , (85,  '2018-02-23 00:00:00' :: timestamp, 'ДЗО')
              , (86,  '2018-03-08 00:00:00' :: timestamp, 'МЖД')
              , (87,  '2018-03-09 00:00:00' :: timestamp, 'МЖД')
              , (88,  '2018-04-30 00:00:00' :: timestamp, 'Первомай')
              , (89,  '2018-05-01 00:00:00' :: timestamp, 'Первомай')
              , (90,  '2018-05-02 00:00:00' :: timestamp, 'Первомай')
              , (91,  '2018-05-09 00:00:00' :: timestamp, 'День Победы')
              , (92,  '2018-06-11 00:00:00' :: timestamp, 'День России')
              , (93,  '2018-06-12 00:00:00' :: timestamp, 'День России')
              , (94,  '2018-11-05 00:00:00' :: timestamp, 'День народного единства')
              , (95,  '2018-12-31 00:00:00' :: timestamp, 'НГ')
              , (96,  '2019-01-01 00:00:00' :: timestamp, 'НГ')
              , (97,  '2019-01-02 00:00:00' :: timestamp, 'НГ')
              , (98,  '2019-01-03 00:00:00' :: timestamp, 'НГ')
              , (99,  '2019-01-04 00:00:00' :: timestamp, 'НГ')
              , (100, '2019-01-07 00:00:00' :: timestamp, 'НГ')
              , (101, '2019-01-08 00:00:00' :: timestamp, 'НГ')
              , (102, '2019-03-08 00:00:00' :: timestamp, 'МЖД')
              , (103, '2019-05-01 00:00:00' :: timestamp, 'Первомай')
              , (104, '2019-05-02 00:00:00' :: timestamp, 'Первомай')
              , (105, '2019-05-03 00:00:00' :: timestamp, 'Первомай')
              , (106, '2019-05-09 00:00:00' :: timestamp, 'День Победы')
              , (107, '2019-05-10 00:00:00' :: timestamp, 'День Победы')
              , (108, '2019-06-12 00:00:00' :: timestamp, 'День России')
              , (109, '2019-11-04 00:00:00' :: timestamp, 'День народного единства')
    )

    ,wt_par as
    (
        select
             id
            ,start_time :: timestamp as i_from_dt
            ,stop_time :: timestamp as i_to_dt
            ,10 :: numeric as i_start_slave_time
            ,19 :: numeric as i_stop_slave_time
        from
            wt_periods
    )

    ,wt_gen_dt as
    (
        select
            pa1.id
            ,pa1.i_from_dt
            ,pa1.i_to_dt
            ,pa1.i_start_slave_time
            ,pa1.i_stop_slave_time
            ,dt 
            ,case when extract(dow from dt) in (6, 0) or sh1.day_off is not null then 0 else 1 end  as is_slave_day
        from wt_par pa1
            cross join generate_series(
                                        date_trunc('day', i_from_dt)
                                      , date_trunc('day', i_to_dt)
                                      , '24 hours' :: interval
                                      ) as dt
            left join wt_holyday  sh1 --табличка с праздничными днями
                on sh1.day_off = dt
    )

select
     id
    ,i_from_dt
    ,i_to_dt
    ,sum( case --дата конца раб дня 
              when is_slave_day = 0
                  then
                      dt + interval '0 hours'
                  else
                      greatest(
                                least(
                                       dt + interval '1 hours' * i_stop_slave_time
                                     , i_to_dt
                                     )
                              , dt + interval '1 hours' * i_start_slave_time
                              , i_from_dt
                              )
          end
          -
          case --дата начала раб дня 
              when is_slave_day = 0
                  then
                      dt + interval '0 hours'
                  else
                      greatest(
                                dt + interval '1 hours' * i_start_slave_time
                              , i_from_dt
                              )
          end )  as sum_slave_mi
from
    wt_gen_dt
group by
     id
    ,i_from_dt
    ,i_to_dt
pg 9.5
with wt_periods(id, start_time, stop_time) as
(
values(1, '2019-03-29 07:00:00'::timestamp, '2019-04-08 14:00:00'::timestamp),
(2, '2019-04-10 07:00:00'::timestamp, '2019-04-10 20:00:00'::timestamp),
(3, '2019-04-11 12:00:00'::timestamp, '2019-04-12 16:07:12'::timestamp),
(4, '2018-12-28 12:00:00'::timestamp, '2019-01-16 16:00:00'::timestamp)
)

,wt_par as
(
select
id
,start_time :: timestamp as i_from_dt
,stop_time :: timestamp as i_to_dt
,10 :: numeric as i_start_slave_time
,19 :: numeric as i_stop_slave_time
from
wt_periods
)

,wt_gen_dt as
(
select
pa1.id
,pa1.i_from_dt
,pa1.i_to_dt
,pa1.i_start_slave_time
,pa1.i_stop_slave_time
,dt
,case
when extract(dow from dt) in (6, 0)
or sh1.day_off is not null
then
0
else
1
end as is_slave_day
from wt_par pa1
cross join generate_series(
date_trunc('day', i_from_dt)
, date_trunc('day', i_to_dt)
, '24 hours' :: interval
) as dt
left join otrsuser.stat_holidays sh1 --табличка с праздничными днями
on sh1.day_off = dt
)

select
id
,i_from_dt
,i_to_dt
,sum( case --дата конца раб дня
when is_slave_day = 0
then
dt + interval '0 hours'
else
greatest(
least(
dt + interval '1 hours' * i_stop_slave_time
, i_to_dt
)
, dt + interval '1 hours' * i_start_slave_time
, i_from_dt
)
end
— case --дата начала раб дня
when is_slave_day = 0
then
dt + interval '0 hours'
else
greatest(
dt + interval '1 hours' * i_start_slave_time
, i_from_dt
)
end ) as sum_slave_mi
from
wt_gen_dt
group by
id
,i_from_dt
,i_to_dt

Информация

В рейтинге
Не участвует
Откуда
Россия
Зарегистрирован
Активность