【问题标题】:Group by data intervals按数据区间分组
【发布时间】:2012-09-19 08:32:14
【问题描述】:

我有一个表,用于存储一段时间内网络上的带宽使用情况。一列将包含日期时间(主键),另一列将记录带宽。每分钟记录一次数据。我们将在其他列中及时记录其他数据。

如果用户每隔 15 分钟(在给定开始和结束日期的 24 小时内)请求数据,是否可以通过单个查询来获取我需要的数据,或者我是否必须编写存储过程/游标去做这个?然后用户可以请求 5 分钟间隔数据等。

我很可能会使用 Postgres,但还有其他更好的 NOSQL 选项吗?

有什么想法吗?

【问题讨论】:

    标签: sql postgresql nosql aggregate-functions generate-series


    【解决方案1】:
    select
        date_trunc('hour', d) + 
        (((extract(minute from d)::integer / 5 * 5)::text) || ' minute')::interval
        as "from",
        date_trunc('hour', d) + 
        ((((extract(minute from d)::integer / 5 + 1) * 5)::text) || ' minute')::interval
        - '1 second'::interval
        as "to",
        sum(random() * 1000) as bandwidth
    from 
        generate_series('2012-01-01', '2012-01-31', '1 minute'::interval) s(d)
    group by 1, 2
    order by 1, 2
    ;
    

    5 分钟的范围。 15 分钟除以 15。

    【讨论】:

    • 哇,谢谢,但我从哪里开始呢? generate_series() 是一个?桌子长什么样?抱歉,对 PostGres 还很陌生,所以请与我联系。
    • @JD:软件名称为PostgreSQL或简称PostgresDetails herePostgreSQL's manual 质量上乘。按照链接(在我的答案中链接到的相关答案中!)了解详细信息和手册的深层链接。
    • @Clodoaldo:事实证明,你的回答已经包含了我发布的大部分内容,除了解释。 +1 第一。
    【解决方案2】:
    WITH t AS (
       SELECT ts, (random()*100)::int AS bandwidth
       FROM   generate_series('2012-09-01', '2012-09-04', '1 minute'::interval) ts
       )
    
    SELECT date_trunc('hour', ts) AS hour_stump
          ,(extract(minute FROM ts)::int / 15) AS min15_slot
          ,count(*) AS rows_in_timeslice               -- optional
          ,sum(bandwidth) AS sum_bandwidth
    FROM   t
    WHERE  ts >= '2012-09-02 00:00:00+02'::timestamptz -- user's time range
    AND    ts <  '2012-09-03 00:00:00+02'::timestamptz -- careful with borders 
    GROUP  BY 1, 2
    ORDER  BY 1, 2;
    

    CTEt 提供的数据类似于您的表可能保存的数据:每分钟一个时间戳 ts 和一个 bandwidth 数字。 (您不需要那部分,而是使用您的表格。)

    对于一个非常相似的问题,这里有一个非常相似的解决方案 - 详细解释了这个特定聚合是如何工作的:

    以下是关于running sums 的类似问题的类似解决方案 - 详细说明和所用各种函数的链接:

    评论中的其他问题

    WITH -- same as above ...
    
    SELECT DISTINCT ON (1,2)
           date_trunc('hour', ts) AS hour_stump
          ,(extract(minute FROM ts)::int / 15) AS min15_slot
          ,bandwidth AS bandwith_sample_at_min15
    FROM   t
    WHERE  ts >= '2012-09-02 00:00:00+02'::timestamptz
    AND    ts <  '2012-09-03 00:00:00+02'::timestamptz
    ORDER  BY 1, 2, ts DESC;
    

    每 15 分钟间隔检索 一个 未聚合的样本 - 从窗口中的最后一个可用行。如果该行没有丢失,这将是第 15 分钟。关键部分是DISTINCT ONORDER BY
    有关所用技术的更多信息,请点击此处:

    【讨论】:

    • 非常感谢。是时候学习了,我根本不知道这是可能的。
    • 如何获取第 15 分钟边界的实际值而不是总和(带宽)?
    • @JD:定义“在第 15 分钟边界”。前一分钟还是后一分钟?你的意思是单行的未汇总值,对吧?
    猜你喜欢
    • 1970-01-01
    • 2013-08-20
    • 2021-02-05
    • 2016-03-05
    • 2022-08-20
    • 2021-07-07
    • 2018-09-24
    • 2021-09-10
    • 1970-01-01
    相关资源
    最近更新 更多