Удалить избыточные диапазоны временных отметок в Postgres SQL - PullRequest
1 голос
/ 17 июня 2019

У меня есть таблица с именами файлов и количеством диапазонов временных отметок для каждого файла, например, как показано ниже:

       filename           mindatetime                 maxdatetime
    monitor_4.dat   2019-04-28 09:00:00 AM      2019-04-29 11:00:00 AM
    monitor_4.dat   2019-04-28 11:00:00 AM      2019-04-29 18:00:00 PM
    monitor_4.dat   2019-04-28 09:30:00 AM      2019-04-29 23:00:00 PM
    monitor_5.dat   2019-04-28 07:00:00 AM      2019-04-28 10:00:00 AM
    monitor_5.dat   2019-04-28 02:00:00 PM      2019-04-28 06:00:00 PM
    monitor_5.dat   2019-04-28 09:00:00 AM      2019-04-28 03:00:00 PM
    monitor_7.dat   2019-04-21 03:06:26.0 AM    2019-05-21 03:06:10.0 AM
    monitor_7.dat   2019-05-21 03:06:10.001 AM  2019-05-24 03:06:11.0 AM
    monitor_7.dat   2019-06-05 03:06:18.001 AM  2019-06-06 03:06:11.0 AM
    monitor_7.dat   2019-05-24 03:06:11.001 AM  2019-06-05 03:06:18.0 AM
    monitor_7.dat   2019-05-12 07:00:10.001 AM  2019-05-13 10:00:10.000 AM
    monitor_7.dat   2019-05-15 09:30:10.001 AM  2019-05-18 11:30:10.000 AM

У меня есть требование удалить избыточные диапазоны временных отметок, т. Е.> Те, которые подпадают под данный диапазон временных отметок. В этом случае для файла "monitor_5.dat" нам нужно время разума как 7 утра, а время максимума как 6 вечера, так как они образуют диапазоны логической минимальной и максимальной отметок времени, которые будут охватывать другие записи.

Таким образом, мой результат должен выглядеть следующим образом:

   filename           mindatetime                 maxdatetime
monitor_4.dat   2019-04-28 09:00:00 AM      2019-04-29 23:00:00 PM
monitor_5.dat   2019-04-28 07:00:00 AM      2019-04-28 06:00:00 PM
monitor_7.dat   2019-04-21 03:06:26.0 AM    2019-06-05 03:06:18.0 AM
monitor_7.dat   2019-05-12 07:00:10.001 AM  2019-05-13 10:00:10.000 AM
monitor_7.dat   2019-05-15 09:30:10.001 AM  2019-05-18 11:30:10.000 AM

Это должно быть достигнуто только через SQL. Любые предложения будут полезны. Я уже исследовал функцию "tsrange", представленную в Postgres, но она не помогает мне полностью.

Ответы [ 2 ]

1 голос
/ 17 июня 2019

Это форма проблемы пробелов и островков.Я бы порекомендовал выяснить, где происходят «перекрытия», а затем использовать кумулятивную сумму для определения групп.Совокупный max() работает для этого:

select filename, min(mindatetime) as mindatetime,
       max(maxdatetime) as maxdatetime
from (select t.*,
             sum(case when prev_maxdatetime >= mindatetime then 0 else 1 end) over
                 (partition by filename order by mindatetime) as grp
      from (select t.*,
                   max(maxdatetime) over
                       (partition by filename
                        order by mindatetime
                        rows between unbounded preceding and 1 preceding
                       ) as prev_maxdatetime
            from t
           ) t
     ) t
group by filename, grp;

Самый внутренний подзапрос определяет, где начинается непересекающийся диапазон времени.Затем средний запрос выполняет кумулятивную сумму этих «запусков», чтобы назначить групповой идентификатор каждой группе.Внешний запрос затем агрегируется по этой группе (и имени файла).

Вы можете выполнить внутренние запросы и посмотреть, какие значения они генерируют.

Здесь - это дБ <> скрипка.Насколько я понимаю, это работает правильно в соответствии с вопросом, который вы задали здесь .Если у вас есть временная задержка, когда вы хотите считать значения одинаковыми / перекрывающимися, задайте новый вопрос с четким объяснением вашей логики.

РЕДАКТИРОВАТЬ:

Если вы хотите одну запись для каждого имени файла, просто используйте агрегирование:

select filename, min(mindatetime) as mindatetime,
       max(maxdatetime) as maxdatetime
from t
group by filename;

Первая версия объединяет строки, между которыми нет пробелов.Это просто занимает самую раннюю и последнюю дату / время.

1 голос
/ 17 июня 2019

Этот ответ только для PostgreSQL;Вы намеренно пометили MySQL?

Вам нужно было бы объединить таблицу с самой собой и удалить записи, содержащиеся в других записях:

DELETE FROM mytable AS a
USING mytable AS b
WHERE a.filename = b.filename
  AND tsrange(a.mindatetime, a.maxdatetime) <@ tsrange(b.mindatetime, b.maxdatetime)
  AND (a.ctid, a.xmin::text) <> (b.ctid, b.xmin::text);

Последнее условие предотвращает сравнение строки ссам по себе.

...