Генерация отчетов временных рядов - PullRequest
0 голосов
/ 16 ноября 2018

Я пытаюсь решить, как создать решение, которое позволит мне запрашивать таблицу с меткой времени, а взамен получать данные временных рядов.Запрос состоит из даты и времени начала / окончания, типа гранулярности (минуты, часа, дня, недели, месяца и года) и значения гранулярности.Попытка использовать в запросе что-то вроде

GROUP BY ROUND(UNIX_TIMESTAMP(created_at) DIV 60)

для получения результатов за одну минуту или DIV 300 за каждые пять минут - это нормально.Проблема заключается еще и в том, чтобы подсчитать месяцы и секунды, которые будут неточными.Я наткнулся на generate_series в PGSQL ( MySQL альтернатива ) и застрял, пытаясь связать их вместе.Как рассчитать количество строк, например, за два дня с 15-минутной детализацией?Это сложный вопрос, который мне, вероятно, придется разбить дальше.

Я уже посетил # 1 и # 2 , но они неполные.Мне кажется, что округление будет разрешено только до определенного уровня, и мне придется ограничить его (т. Е. В течение 2 месяцев не может быть часового разбивки).

РЕДАКТИРОВАНИЕ

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

SELECT DATE_FORMAT(MIN(created_at),'%d/%m/%Y %H:%i:%s' as date,
COUNT(*) AS count FROM guests
GROUP BY ROUND(UNIX_TIMESTAMP(created_at) / 300)

Группировка будет выполняться только на основе минимального значения.Но вопрос остается открытым - действительно ли лучший подход - действительно пройти период времени с использованием значения гранулярности и «разрезать» данные таким образом, не теряя слишком много точности?

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

1 Ответ

0 голосов
/ 16 ноября 2018

Допустим, у вас есть гигантская таблица measure с двумя столбцами datestamp и temp.

Допустим, вы хотите видеть температуру каждые шесть минут (10 раз в час) в течение последней недели. Вы можете делать такие вещи. Мы скоро дойдем до определения trunc.

  SELECT trunc(datestamp) datestamp, AVG(temp) temp
    FROM measure
   WHERE datestamp >= CURDATE() - INVERVAL 7 DAY
  GROUP BY trunc(datestamp)
  ORDER BY trunc(datestamp)

Это работает для любого разумного определения trunc. В этом случае trunc(t) возвращает начало шестиминутного периода, в котором происходит t. Итак, trunc('1942-12-07 08:45:17') дает 1942-12-07 08:42:00).

Вот запрос, который работает для каждого шестиминутного интервала.

  SELECT DATE_FORMAT(datestamp,'%Y-%m-%d %H:00') +
            INTERVAL (MINUTE(datestamp) -
                      MINUTE(datestamp) MOD 6) datestamp, 
         AVG(temp) temp
    FROM measure
   WHERE datestamp >= CURDATE() - INVERVAL 7 DAY
   GROUP BY DATE_FORMAT(datestamp,'%Y-%m-%d %H:00') +
            INTERVAL (MINUTE(datestamp) -
                      MINUTE(datestamp) MOD 6)
  ORDER BY 1

При этом используется встроенная арифметика даты, а не арифметика метки времени unix.

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

DELIMITER $$
DROP FUNCTION IF EXISTS TRUNC_N_MINUTES$$
CREATE
  FUNCTION TRUNC_N_MINUTES(datestamp DATETIME, n INT)
  RETURNS DATETIME DETERMINISTIC NO SQL
  COMMENT 'truncate to N minute boundary. For example,
           TRUNCATE_N_MINUTES(sometime, 15) gives the nearest
           preceding quarter hour'
  RETURN DATE_FORMAT(datestamp,'%Y-%m-%d %H:00') +
                INTERVAL (MINUTE(datestamp) -
                          MINUTE(datestamp) MOD n) MINUTE$$
DELIMITER ;

Тогда ваш запрос скажет

  SELECT TRUNC_N_MINUTES(datestamp, 6) datestamp, AVG(temp) temp
    FROM measure
   WHERE datestamp >= CURDATE() - INVERVAL 7 DAY
  GROUP BY TRUNC_N_MINUTES(datestamp, 6)
  ORDER BY TRUNC_N_MINUTES(datestamp, 6)

Если вы хотите суммировать по 5, 10, 15 или минутным границам (три элемента в час), просто используйте это число вместо 6.

Вам понадобятся различные функции trunc() для часов и т. Д.

Функция trunc() для ежедневных сводок - DATE(datestamp). Для ежемесячных сводок это LAST_DAY(datestamp). Например,

  SELECT LAST_DAY(datestamp) month_ending, AVG(temp) temp
    FROM measure
  GROUP BY LAST_DAY(datestamp) 
  ORDER BY LAST_DAY(datestamp) 

дает ежемесячную сводку.

...