3

我正在尝试研究如何创建一个解决方案,该解决方案将允许我查询具有时间戳的表,并作为回报获得时间序列数据。请求由开始/结束日期和时间、粒度类型(分钟、小时、日、周、月和年)和粒度值组成。尝试在查询中使用类似

GROUP BY ROUND(UNIX_TIMESTAMP(created_at) DIV 60)

每一分钟得到结果,或者每五分钟得到DIV 300就可以了。问题在于计算月份和年份的秒数,这将是不准确的。我偶然发现了 PGSQL 中的 generate_series(MySQL 替代方案),并且一直试图将它们联系在一起。如何以 15 分钟的粒度计算行数,例如两天?这是一个复杂的问题,我可能不得不进一步分解。

我已经访问过#1#2,但它们不完整。对我来说,四舍五入似乎只允许达到一定的水平,我不得不限制它(即 .for 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 分钟间隔的时间戳,将数据分组并生成聚合),而不分割原始时间戳以生成四舍五入的近似值。

4

1 回答 1

2

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

产生逐月总结。

于 2018-11-16T18:34:57.173 回答