在一个时间间隔内生成时间戳范围并查询所有重叠事件

Generate timestamp ranges over an interval and query for all overlapping events

我想在一个时间间隔内生成一系列时间戳范围,并为所有重叠事件查询 table。我 几乎 在那里,但对 SQL 还是很陌生,似乎无法克服这个困难。

为了测试,我构建了一个 table 包含一系列事件,每个事件都发生在一个日期时间范围内:

CREATE TABLE event (id int, order_dates tsrange, flow int);
INSERT INTO event VALUES
    (1,'[2021-09-01 10:55:01,2021-09-04 15:16:01)',50),
    (2,'[2021-08-15 20:14:27,2021-08-18 22:19:27)',36),
    (3,'[2021-08-03 12:51:47,2021-08-05 11:28:47)',41),
    (4,'[2021-08-17 09:14:30,2021-08-20 13:57:30)',29),
    (5,'[2021-08-02 20:29:07,2021-08-04 19:19:07)',27),
    (6,'[2021-08-26 02:01:13,2021-08-26 08:01:13)',39),
    (7,'[2021-08-25 23:03:25,2021-08-27 03:22:25)',10),
    (8,'[2021-08-12 23:40:24,2021-08-15 08:32:24)',26),
    (9,'[2021-08-24 17:19:59,2021-08-29 00:48:59)',5),
    (10,'[2021-09-01 02:01:17,2021-09-02 12:31:17)',48),
    (11,'[2021-08-16 01:30:17,2021-08-16 01:46:17)',37),
    (12,'[2021-08-06 09:35:23,2021-08-10 09:19:23)',21),
    (13,'[2021-08-17 06:12:21,2021-08-20 04:40:21)',12),
    (14,'[2021-08-21 05:45:03,2021-08-23 16:24:03)',38),
    (15,'[2021-08-10 01:55:48,2021-08-10 23:23:48)',39),
    (16,'[2021-08-28 06:26:59,2021-08-29 21:25:59)',28);

我可以使用以下查询以 60 分钟(或任何值)为间隔生成一系列时间戳,并获取所有重叠的事件(并获取在每个时间戳发生的事件的计数)。效果很好:

SELECT row_number() OVER () AS id,
      grid.bin,
      count(DISTINCT t.id) AS id_count,
FROM (
   SELECT generate_series('2021-08-01 00:00:00'::timestamp,
                          '2021-08-07 23:59:59'::timestamp, interval '60 min') AS bin
   FROM event
   ) grid
LEFT JOIN event t ON t."order_dates" @> grid.bin
GROUP  BY grid.bin
ORDER  BY grid.bin;

https://www.db-fiddle.com/f/5P4G7DCY2vdZfLFSi5cA9p/0

我也知道我可以使用此查询生成具有给定间隔的时间戳 范围 而不仅仅是时间戳。

SELECT tsrange((lag(bin) OVER()), bin, '[)')
FROM generate_series(
    '2021-08-01 12:00:00'::timestamp,
    '2021-08-07 12:00:00',
    '60 minute')
AS a OFFSET 1;

https://www.db-fiddle.com/f/nPKTb82SknB3XYi5exrtkz/1

但我似乎无法弄清楚如何组合这两个查询,将第一个查询的 generate_series 部分替换为第二个查询。我知道我需要使用 &&(重叠)而不是 @>(包含元素)。

如果您能帮助我们解决这个问题,我们将不胜感激。这可能很简单,但我不确定在解决这样的问题时甚至要搜索什么。

FROM子句中使用generate_series

SELECT row_number() OVER (ORDER BY lower(grid.bin)) AS id,  -- needs ORDER BY
       grid.bin,
       count(t.id) AS id_count  -- no need for DISTINCT
FROM (SELECT tsrange(
                lag(t) OVER (ORDER BY t),
                t
             )
      FROM generate_series(
              '2021-08-01 00:00:00'::timestamp,
              '2021-08-07 23:59:59'::timestamp,
              interval '60 min'
           ) AS times(t)
     ) AS grid(bin)
LEFT JOIN event t ON t."order_dates" @> grid.bin
GROUP BY grid.bin
ORDER BY lower(grid.bin);