按 5、10、15 分钟块对带时间戳的记录进行分组

Group timestamped record by 5, 10, 15 minutes block

我的 table,

中有以类似格式存储的每分钟财务记录
         dt          |   open   |   high   |   low    |  close   |  vol  
---------------------+----------+----------+----------+----------+-------
 2018-05-04 15:30:00 | 171.0000 | 171.3000 | 170.9000 | 171.0000 | 42817
 2018-05-04 15:29:00 | 170.8000 | 171.0000 | 170.8000 | 170.9500 | 32801
 2018-05-04 15:28:00 | 170.8500 | 171.0000 | 170.8000 | 170.8000 | 22991
 2018-05-04 15:27:00 | 170.8500 | 170.8500 | 170.7500 | 170.8000 | 40283
 2018-05-04 15:26:00 | 170.9500 | 171.0000 | 170.8000 | 170.8500 | 46636

等等。

我想将它们分组为 5 分钟、10 分钟、60 分钟的块,就像烛台一样。使用 date_trunc('hour', dt) 是不可能的,因为我想将它们分组为最后 60 分钟、最后 15 分钟等块

我正在使用 PostgreSQL。

您可以使用generate_series()创建您想要的任何范围

SQL DEMO:

SELECT dd as start_range, dd + '30 min'::interval as end_range
FROM generate_series
        ( '2018-05-05'::timestamp 
        , '2018-05-06'::timestamp
        , '30 min'::interval) dd
        ;

然后检查您的记录是否在该范围内。

您应该使用 GROUP BY 和 :

floor(extract('epoch' from dt) / 300)

以 5 分钟为间隔对数据进行分组。 300 是 5 分钟中的秒数。因此,如果您想要 10 分钟,则除以 600。如果您想要 1 小时,则除以 3600。

如果您希望间隔从 00 05 10 开始,请使用 floor()。如果您希望它们在 00、05、10 结束,请使用 ceil()

SELECT子句中,您应该将GROUP BY中使用的Unix epoch重新转换为timestamp 使用

to_timestamp(floor((extract('epoch' from dt) / 300)) * 300)  as ts

不清楚您是否希望在同一个查询中获得所有 "block" 结果,如果您想要烛台图,我假设是的。我还从逻辑上推断出每列的正确聚合函数(MIN、MAX、AVG、SUM),遵循它们的名称。您可能需要对此进行调整。

我们开始了:

 SELECT '5 minutes' as block,
        to_timestamp(floor((extract('epoch' from dt) / 300)) * 300)  as ts, 
        round(AVG(open),4) as avg_open,  
        round(MAX(high),4) as max_high, 
        round(MIN(low),4) as min_low, 
        round(AVG(close),4) as avg_close,  
        SUM(vol) as sum_vol  
 FROM mytable
 GROUP BY floor(extract('epoch' from dt) / 300)

 UNION ALL

  SELECT '10 minutes' as block,
        to_timestamp(floor((extract('epoch' from dt) / 600)) * 600)  as ts, 
        round(AVG(open),4) as avg_open,  
        round(MAX(high),4) as max_high, 
        round(MIN(low),4) as min_low, 
        round(AVG(close),4) as avg_close,  
        SUM(vol) as sum_vol  
 FROM mytable
 GROUP BY floor(extract('epoch' from dt) / 600)

  UNION ALL

  SELECT '1 hour' as block,
        to_timestamp(floor((extract('epoch' from dt) / 3600)) * 3600)  as ts, 
        round(AVG(open),4) as avg_open,  
        round(MAX(high),4) as max_high, 
        round(MIN(low),4) as min_low, 
        round(AVG(close),4) as avg_close,  
        SUM(vol) as sum_vol  
 FROM mytable
 GROUP BY floor(extract('epoch' from dt) / 3600)

结果:

    block       ts                  avg_open    max_high    min_low     avg_close   sum_vol
    5 minutes   04.05.2018 17:30:00 171         171,3       170,9       171         42817
    5 minutes   04.05.2018 17:25:00 170,8625    171         170,75      170,85      142711
    10 minutes  04.05.2018 17:20:00 170,8625    171         170,75      170,85      142711
    10 minutes  04.05.2018 17:30:00 171         171,3       170,9       171         42817
    1 hour      04.05.2018 17:00:00 170,89      171,3       170,75      170,88      185528

REXTESTER

上测试