Oracle - Присоединяйтесь 2 периода времени - PullRequest
0 голосов
/ 20 декабря 2018

У меня есть 2 строки с 2 периодами времени, которые пересекаются.Например:

---------------------------------------------
|     START_DATE      |      END_DATE       |
---------------------------------------------
| 01/01/2018 08:00:00 | 01/01/2018 09:30:00 |
| 01/01/2018 08:30:00 | 01/01/2018 10:00:00 |
---------------------------------------------

В течение 30 минут оба периода пересекаются.Я хочу избежать этого.Я хотел бы объединить обе строки в одном столбце, указав дату начала как более старую, а дату окончания - как более новую:

---------------------------------------------
|     START_DATE      |      END_DATE       |
---------------------------------------------
| 01/01/2018 08:00:00 | 01/01/2018 10:00:00 |
---------------------------------------------

Есть ли у вас какие-либо идеи, как получить желаемое решение с помощьюSQL-предложение?

Ответы [ 2 ]

0 голосов
/ 20 декабря 2018

Если все, что у вас есть, это набор диапазонов дат, без каких-либо других коррелирующих или ограничивающих критериев, и вы хотите уменьшить его до набора непересекающихся диапазонов, вы можете сделать это с помощью рекурсивного запроса, подобного этому:

with recur(start_date, end_date) as (
  select * from yourdata yd 
   where not exists (select 1 from yourdata cyd 
                      where yd.start_Date between cyd.start_date and cyd.end_date
                        and (yd.start_date <> cyd.start_date or yd.end_date <> cyd.end_date))
  union all
  select r.start_date
       , yd.end_date
    from recur r
    join yourdata yd
      on r.start_date < yd.start_date
     and yd.start_date <= r.end_date
     and r.end_date < yd.end_date
)
select start_date, max(end_date) end_Date from recur group by start_Date;

В этом запросе якорь (часть перед объединением всех) выбирает все записи, дата начала которых не содержится ни в каком другом диапазоне.

Рекурсивная часть (часть после объединения всех) затем выберите диапазоны, которые расширяют текущий диапазон.В обеих половинах возвращается исходная дата начала, в то время как в рекурсивной части возвращается новая расширенная дата окончания.Это приводит к набору перекрывающихся диапазонов с общей датой начала.

Наконец, выходной запрос возвращает дату начала и максимальную дату окончания, сгруппированные по дате начала.

0 голосов
/ 20 декабря 2018

Для двух строк просто используйте greatest() и least().Но проблема в том, что у вас много строк, которые могут перекрываться по-разному.Вы можете:

  • добавлять номера строк в каждую строку,
  • назначать группы для перекрывающихся периодов, используя рекурсивный запрос,
  • группировать данные, используя это значение, и находить мин и макс.даты в каждой группе.

Демоверсия dbfiddle

with 
    r(rn, start_date, end_date) as (
        select row_number() over(order by start_date), start_date, end_date from t ),
    c(rn, start_date, end_date, grp) as (
        select rn, start_date, end_date, 1 from r where rn = 1
        union all
        select r.rn, 
               case when r.start_date <= c.end_date and c.start_date <= r.end_date 
                    then least(r.start_date, c.start_date) else r.start_date end,
               case when r.start_date <= c.end_date and c.start_date <= r.end_date 
                    then greatest(r.end_date, c.end_date) else r.end_date end,
               case when r.start_date <= c.end_date and c.start_date <= r.end_date 
                    then grp else grp + 1 end
          from c join r on r.rn = c.rn + 1)
select min(start_date), max(end_date) from c group by grp
...