PostgreSQL - 查询以显示哪些时间间隔包含数据

时间:2017-06-02 09:38:06

标签: sql postgresql

我有一个包含带时间戳数据的表。我尝试构建一个每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;

但是,如何用不包含数据的间隔填写此内容?

1 个答案:

答案 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)