Oracle — Перечислите каждый отдельный день с часами в месяце

#sql #oracle #datetime #recursive-query

#sql #Oracle #дата и время #рекурсивный запрос

Вопрос:

Я делаю какую-то панель мониторинга и обнаружил, что у меня нет таблицы, включающей все нужные мне даты. Мои подзапросы должны быть подключены по ДАТЕ (DD.MM , ГГГГ) и ЧАСОВ (HH24). Однако я застрял с шаблоном.

Я перечислил все дни месяца через

 select to_date('1.' || to_CHAR(sysdate, 'MM.YYYY'), 'dd.mm.yyyy')   level - 1 as month
   from dual
  connect by level <= TO_CHAR(LAST_DAY(sysdate), 'DD')
  

а также перечислил все часы за день через

 select to_date(to_char(sysdate, 'DD.MM.YYYY'), 'dd.mm.yyyy')   1 / 24*(level - 1)
   from dual
  connect by level <= 24
  

Когда я объединяю его с rownum = 1 в месяц, поэтому я получаю только 1 день, он работает…

 select to_date(to_char(mesic, 'DD.MM.YYYY'), 'dd.mm.yyyy')   1 / 24*(level - 1)
   from 
(select *
           from (select to_date('1.' || to_CHAR(sysdate, 'MM.YYYY'), 'dd.mm.yyyy')   level - 1 as mesic
                   from dual
                  connect by level <= TO_CHAR(LAST_DAY(sysdate), 'DD'))
          where rownum = 1)

  connect by level <= 24
  

Однако, когда я удаляю условие rownum, я получаю ошибку, что я получил максимальное количество строк.

По моей логике это должно быть как 24 (часов) * 31 (дней в текущем месяце) = 744. Мои обычные отчеты dashborads часто содержат около 5000 строк, так что это не должно быть проблемой.

Спасибо вам за советы, ребята

Ответ №1:

Для меня это выглядит так просто, как

 select trunc(sysdate, 'mm')   (level - 1) / 24 datum
from dual
connect by level <= (add_months(trunc(sysdate, 'mm'), 1) - trunc(sysdate, 'mm')) * 24;

DATUM
----------------
01.08.2020 00:00
01.08.2020 01:00
01.08.2020 02:00
<snip>
31.08.2020 21:00
31.08.2020 22:00
31.08.2020 23:00

744 rows selected.
  

Комментарии:

1. @DominikVana . , , Если этот (или другой ответ) отвечает на ваш вопрос, то вам следует принять один из них.

Ответ №2:

Если вы хотите сгенерировать все часы в текущем месяце, вы можете сделать:

 with cte (dt) as (
    select trunc(sysdate, 'month') from dual
    union all
    select dt   interval '1' hour 
    from cte 
    where dt   interval '1' hour < trunc(sysdate, 'month')   interval '1' month
)
select * from cte   
  

Мы можем уменьшить количество итераций, сгенерировав дни и часы отдельно, а затем перекрестно объединив их:

 with 
    days (dy) as (
        select trunc(sysdate, 'month') from dual
        union all
        select dy   interval '1' day 
        from days 
        where dy   interval '1' day < trunc(sysdate, 'month')   interval '1' month
    ),
    hours (hh) as (
        select 0 from dual
        union all 
        select hh   1 from hours where hh < 23
    )
select d.dy   h.hh  * interval '1' hour dt
from days d
cross join hours h