我有一个包含带时间戳数据的表。我尝试构建一个每5分钟间隔返回一行的查询,如果时间戳落在该时间间隔内,则列为TRUE
,如果没有,则为FALSE
,开始在数据的最早时间戳,最迟结束。
我可以得到包含这样的时间戳的5分钟间隔:
SELECT DISTINCT DATE_TRUNC('hour', t) + ( EXTRACT(minute FROM t)::int / 5 * interval '5 min' ) AS t,
TRUE AS val
FROM data_table
ORDER BY t;
但是,如何用不包含数据的间隔填写此内容?
答案 0 :(得分:1)
我需要一个函数将时间戳舍入到前5分钟的边界:
CREATE OR REPLACE FUNCTION trunc_five_min(timestamp with time zone)
RETURNS timestamp with time zone
LANGUAGE sql STABLE AS
$$SELECT date_trunc('hour', $1)
+ date_trunc(
'minute',
($1 - date_trunc('hour', $1)) / 5
) * 5$$;
此函数将内联到查询中,因此您可以将其视为符号快捷方式。
当我有这样的时间序列表:
TABLE samples ORDER BY ts;
┌────────────────────────┐
│ ts │
├────────────────────────┤
│ 2017-06-02 11:58:30+02 │
│ 2017-06-02 12:00:00+02 │
│ 2017-06-02 12:03:00+02 │
│ 2017-06-02 12:17:00+02 │
│ 2017-06-02 12:17:22+02 │
└────────────────────────┘
(5 rows)
我可以使用此查询生成所需的结果:
WITH lim AS (SELECT trunc_five_min(min(ts)) AS min,
trunc_five_min(max(ts)) AS max
FROM samples)
SELECT i.i AS interval_start,
count(s.ts) AS num_samples
FROM lim
CROSS JOIN LATERAL generate_series(lim.min, lim.max, INTERVAL '5 minutes') i
LEFT JOIN samples s
ON s.ts >= i AND s.ts < i + INTERVAL '5 minutes'
GROUP BY i.i ORDER BY i.i;
┌────────────────────────┬─────────────┐
│ interval_start │ num_samples │
├────────────────────────┼─────────────┤
│ 2017-06-02 11:55:00+02 │ 1 │
│ 2017-06-02 12:00:00+02 │ 2 │
│ 2017-06-02 12:05:00+02 │ 0 │
│ 2017-06-02 12:10:00+02 │ 0 │
│ 2017-06-02 12:15:00+02 │ 2 │
└────────────────────────┴─────────────┘
(5 rows)