基于时间间隔计算分组平均值

时间:2014-06-21 14:44:38

标签: sql postgresql

在postgres表中,我以10秒的间隔存储对象的速度。白天不能每10秒钟提供一次这些值;所以可能是今天没有线16:39:40

假设不存在的行表示速度为0,查询如何获得包含给定日期1分钟(或30秒或n秒)间隔的平均速度的关系。

speed_table
id( int ,pk) ts(时间戳) 速度(数字)

我已经构建了这个查询,但我遇到了一些重要问题:

SELECT 
    date_trunc('minute', ts) AS truncated, 
    avg(speed)
FROM speed_table AS t 
WHERE ts >= '2014-06-21 00:00:00'
AND ts <= '2014-06-21 23:59:59'
AND condition2 = 'something'
GROUP BY date_trunc('minute', ts)
ORDER BY truncated
  • 如何更改date_trunc函数结果以外的其他内容的时间间隔,例如5分30秒?
  • 如何在剩余的当天添加不可用的行?

2 个答案:

答案 0 :(得分:3)

此特定示例的简单快速解决方案:

SELECT date_trunc('minute', ts) AS minute
     , sum(speed)/6 AS avg_speed
FROM   speed_table AS t 
WHERE  ts >= '2014-06-21 0:0'
AND    ts <  '2014-06-20 0:0'  -- exclude dangling corner case
AND    condition2 = 'something'
GROUP  BY 1
ORDER  BY 1;

您需要将缺失的行分解为&#34; 0 speed&#34;。由于一分钟有6个样本,只需求和除以6.缺少的行隐含地计算为0

这几分钟没有返回任何行的行。avg_speed表示缺少结果行0

任意间隔的一般查询

适用于the manual for date_trunc()中列出的所有时间间隔:

SELECT date_trunc('minute', g.ts) AS ts_start
     , avg(COALESCE(speed, 0))    AS avg_speed
FROM  (SELECT generate_series('2014-06-21 0:0'::timestamp
                            , '2014-06-22 0:0'::timestamp
                            , '10 sec'::interval) AS ts) g
LEFT   JOIN speed_table t USING (ts)
WHERE (t.condition2 = 'something' OR
       t.condition2 IS NULL)                -- depends on actual condition!
AND    g.ts <> '2014-06-22 0:0'::timestamp  -- exclude dangling corner case
GROUP  BY 1
ORDER  BY 1;

有问题的部分是另外的未知条件。你需要定义它。并确定generate_series提供的缺失行是否应该通过测试(这可能很棘手!) 我让它们传递给我的示例(以及所有其他具有NULL值的行)。

比较:
PostgreSQL: running count of rows for a query 'by minute'

任意间隔:
Truncate timestamp to arbitrary intervals

对于完全任意的间隔,请考虑@Clodoaldo's math based on epoch values或使用经常被忽略的函数width_bucket()。例如:
Aggregating (x,y) coordinate point clouds in PostgreSQL Aggregating (x,y) coordinate point clouds in PostgreSQL

答案 1 :(得分:2)

如果您发布了一些数据,则可以进行测试,这样可能会包含错误。指出它们包括错误消息,以便我可以解决。

select
    to_timestamp(
        (extract(epoch from ts)::integer / (60 * 2)) * (60 * 2)
    ) as truncated,
    avg(coalesce(speed, 0)) as avg_speed
from
    generate_series (
        '2014-06-21 00:00:00'::timestamp,
        '2014-06-22'::timestamp - interval '1 second',
        '10 seconds'
    ) ts (ts)
    left join
    speed_table t on ts.ts = t.ts and condition2 = 'something'
group by 1
order by 1

该示例按30秒分组。它是自1970-01-01 00:00:00epoch)除以120后的秒数。当您想要按5分钟分组时除以12(60/5)。

示例中的generate_series以1秒的间隔生成时间戳。速度表为left outer join,因此填补了空白。当速度为null时,coalesce返回0.