【问题标题】:calculating average with grouping based on time intervals基于时间间隔的分组计算平均值
【发布时间】:2014-06-21 14:44:37
【问题描述】:

在 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 秒)之外,我如何更改间隔?
  • 如何添加当天剩余时间不可用的行?

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:

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

    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;
    

    您需要将缺失的行视为“0 速度”。由于一分钟有 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

    【讨论】:

    • 未知条件只是一个整数选择器:例如where t.objectid= 56
    • @stUrb:棘手的部分:t.objectid 可以为 NULL 吗?我们是否假设缺少行来满足条件?被条件删除的行和不存在的行有什么区别?
    • 对象ID不能为NULL。这些表存储了多个资产的速度。 object_id 只是分隔不同的资产。
    【解决方案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:00 (epoch) 除以 120 以来的秒数。当您想按 5 分钟分组时,除以 12 (60 / 5)。

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

    【讨论】:

    • @Erwin 好的。我想我修好了。
    猜你喜欢
    • 1970-01-01
    • 2019-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-18
    • 1970-01-01
    • 2020-07-12
    • 2021-02-08
    相关资源
    最近更新 更多