如何在 postgres 中将时间戳数据装入 n 分钟的桶中

Awe*_*own 3 postgresql

我有以下有效的查询,将带时间戳的“观察”分箱到其边界由 bin 表定义的桶中:

SELECT
  count(id),
  width_bucket(
      time :: TIMESTAMP,
      (SELECT ARRAY(SELECT start_time
                    FROM bins
                    WHERE owner_id = 'some id'
                    ORDER BY start_time ASC) :: TIMESTAMP[])
  ) bucket
FROM observations
WHERE owner_id = 'some id'
GROUP BY bucket
ORDER BY bucket;
Run Code Online (Sandbox Code Playgroud)

我想修改它以允许查询从指定时间戳开始的任意 n 分钟 bin,而不必从实际的“bins”表中提取。

也就是说,给定开始时间、以分钟为单位的“bin 宽度”和 bin 数量,有没有办法生成时间戳数组以传递到函数中width_bucket

或者,是否有不同/更简单的方法来获得相同的结果?

kli*_*lin 5

使用该功能generate_series(start, stop, step interval),例如

select array(
    select generate_series(
        timestamp '2018-04-15 00:00', 
        '2018-04-15 01:00', 
        '30 minutes'))

                               array                                
---------------------------------------------------------------------
 {"2018-04-15 00:00:00","2018-04-15 00:30:00","2018-04-15 01:00:00"}
(1 row)
Run Code Online (Sandbox Code Playgroud)

Db<>fiddle中的示例


Nic*_*ise 5

上面的答案似乎可以满足您的要求,但从 PostgreSQL 14 开始,现在有一个函数date_bin仅用于对时间戳进行分箱。

引用文档:

date_bin(stride,source,origin)

sourcetimestamp是or类型的值表达式timestamp with time zone。(类型的值date自动转换为timestamp。)stride是类型 的值表达式interval。返回值同样是timestampor类型timestamp with time zone,它标记了放入的 bin 的开始source

例子:

SELECT date_bin('15 minutes', TIMESTAMP '2020-02-11 15:44:17', TIMESTAMP > '2001-01-01');
Result: 2020-02-11 15:30:00

SELECT date_bin('15 minutes', TIMESTAMP '2020-02-11 15:44:17', TIMESTAMP '2001-01-01 00:02:30');
Result: 2020-02-11 15:32:30
Run Code Online (Sandbox Code Playgroud)

在完整单位(1 分钟、1 小时等)的情况下,它给出与类似date_trunc调用相同的结果,但不同之处在于date_bin可以截断为任意间隔。

间隔stride必须大于零,并且不能包含月或更大的单位。

我想特别注意这条线

返回值[...]标记了源所在容器的开始位置

这意味着输入时间戳将始终通过“向下舍入”进行分箱,而不是分箱到最接近的分箱。例如,如果你这样做:

SELECT date_bin('15 minutes', TIMESTAMP '2020-02-11 15:44:17', TIMESTAMP > '2001-01-01');
Result: 2020-02-11 15:30:00

SELECT date_bin('15 minutes', TIMESTAMP '2020-02-11 15:44:17', TIMESTAMP '2001-01-01 00:02:30');
Result: 2020-02-11 15:32:30
Run Code Online (Sandbox Code Playgroud)

那么结果将是2020-10-13 00:00:00(向下舍入 59 分 59 秒),而不是2021-10-13 01:00:00(距离提供的时间戳仅一秒)。因此,该date_bin函数所做的事情与您所要求的略有不同,但我认为这对于将来来到这里的任何人来说都是很好的。