生成时间序列报告
Generating time series reports
我正在尝试创建一个解决方案,让我可以查询具有时间戳的 table,并在 return 中获取时间序列数据。该请求由 start/end 日期和时间、粒度类型(分钟、小时、日、周、月和年)和粒度值组成。尝试在查询中使用
GROUP BY ROUND(UNIX_TIMESTAMP(created_at) DIV 60)
一分钟出结果,或者DIV每五分钟300个就可以了。问题在于计算月份和年份的秒数是不准确的。我在 PGSQL (MySQL alternative) 中偶然发现了 generate_series,并且一直试图将它们联系在一起。例如,如何以 15 分钟的粒度计算两天的行数?这是一个复杂的问题,我可能不得不进一步分解。
我已经访问过 and #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)
它只会根据最小值进行分组。但问题仍然存在 - 最好的方法真的是使用粒度值和 "slice" 数据在不损失太多准确性的情况下通过时间段吗?
似乎唯一的方法是 运行 对一组数据进行子查询(即在两个月的时间段内,生成 15 分钟间隔的时间戳,将数据分组并生成聚合) 而不划分原始时间戳以生成四舍五入的近似值。
假设您有一个巨大的 table 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)
returns 发生 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)
生成逐月摘要。
我正在尝试创建一个解决方案,让我可以查询具有时间戳的 table,并在 return 中获取时间序列数据。该请求由 start/end 日期和时间、粒度类型(分钟、小时、日、周、月和年)和粒度值组成。尝试在查询中使用
GROUP BY ROUND(UNIX_TIMESTAMP(created_at) DIV 60)
一分钟出结果,或者DIV每五分钟300个就可以了。问题在于计算月份和年份的秒数是不准确的。我在 PGSQL (MySQL alternative) 中偶然发现了 generate_series,并且一直试图将它们联系在一起。例如,如何以 15 分钟的粒度计算两天的行数?这是一个复杂的问题,我可能不得不进一步分解。
我已经访问过
编辑
这给了我错误的印象——我不必使用如下查询来计算基于秒数的每月数字:
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)
它只会根据最小值进行分组。但问题仍然存在 - 最好的方法真的是使用粒度值和 "slice" 数据在不损失太多准确性的情况下通过时间段吗?
似乎唯一的方法是 运行 对一组数据进行子查询(即在两个月的时间段内,生成 15 分钟间隔的时间戳,将数据分组并生成聚合) 而不划分原始时间戳以生成四舍五入的近似值。
假设您有一个巨大的 table 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)
returns 发生 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)
生成逐月摘要。