我有以下有效的查询,将带时间戳的“观察”分箱到其边界由 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?
或者,是否有不同/更简单的方法来获得相同的结果?
使用该功能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中的示例。
上面的答案似乎可以满足您的要求,但从 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。例子:
Run Code Online (Sandbox Code Playgroud)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在完整单位(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函数所做的事情与您所要求的略有不同,但我认为这对于将来来到这里的任何人来说都是很好的。