生成时间序列报告

时间:2018-11-16 12:46:19

标签: mysql aggregate-functions datestamp

我正在尝试找出一种解决方案,该解决方案将允许我查询具有时间戳的表,并获得时间序列数据。该请求包括开始/结束日期和时间,粒度类型(分钟,小时,天,周,月和年)和粒度值。尝试在查询中使用

之类的东西
GROUP BY ROUND(UNIX_TIMESTAMP(created_at) DIV 60)

每分钟获取结果,或者每五分钟DIV 300即可。问题在于进一步计算月份和年份的秒数,这将是不准确的。我偶然发现了PGSQL(MySQL alternative)中的generate_series,并试图将它们绑在一起。如何以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 :(得分:1)

假设您有一个巨大的表measure,其中有两列datestamptemp

假设您要查看上一周每六分钟(每小时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或分钟边界(每小时3个项目)进行汇总,只需使用该数字代替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) 

产生每月的摘要。