修改 Postgres 查询以使用 generate_series 对几个连续范围间隔中的每一个进行总体求和

Modify Postgres query to use generate_series for overall summation over each of several consecutive range intervals

我对 SQL 还是很陌生,来自以 ORM 为中心的环境,所以请耐心等待。

以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); -- etc

下面的查询执行以下操作:

(这里,'the range' 是从 2021-08-03T00:00:002021-08-04T00:00:00

  1. 对于与 the range
  2. 重叠的每个事件
  3. Trim order_dates 的 Lower 和 Upper 时间戳值到 the range
  4. 的边界
  5. 将每个适用事件的剩余持续时间乘以 event.flow
  6. 对最终单值输出的所有相乘值求和

Basically, I get all of the events that overlap the range, but only calculate the total value based on the portion of each event that is within the range.

SELECT SUM("total_value")
FROM
    (SELECT (EXTRACT(epoch
        FROM (LEAST(UPPER("event"."order_dates"), '2021-08-04T00:00:00'::timestamp) - GREATEST(LOWER("event"."order_dates"), '2021-08-03T00:00:00'::timestamp)))::INTEGER * "event"."flow") AS "total_value"
    FROM "event"
    WHERE "event"."order_dates" && tsrange('2021-08-03T00:00:00'::timestamp, '2021-08-04T00:00:00'::timestamp, '[)')
    GROUP BY "event"."id",
        GREATEST(LOWER("event"."order_dates"), '2021-08-03T00:00:00'::timestamp),
        LEAST(UPPER("event"."order_dates"), '2021-08-04T00:00:00'::timestamp),
        EXTRACT(epoch
            FROM (LEAST(UPPER("event"."order_dates"), '2021-08-04T00:00:00'::timestamp) - GREATEST(LOWER("event"."order_dates"), '2021-08-03T00:00:00'::timestamp)))::INTEGER, (EXTRACT(epoch
                FROM (LEAST(UPPER("event"."order_dates"), '2021-08-04T00:00:00'::timestamp) - GREATEST(LOWER("event"."order_dates"), '2021-08-03T00:00:00'::timestamp)))::INTEGER * "event"."flow")) subquery

DB<>Fiddle 证明了这一点:https://www.db-fiddle.com/f/jMBtKKRS33Qf2FEoY5EdPA/1

这个查询开始时是一组复杂的 django 注释和聚合,我对其进行了简化,删除了这个问题不需要的部分。


因此,通过以上,我得到了输入范围内的单个总值(在本例中为 1 天范围)。

但我希望能够使用 generate_series 对几个连续范围间隔中的每一个执行相同的总体求和

例如:查询以下每个范围内的总数:

['2021-08-01T00:00:00', '2021-08-02T00:00:00')
['2021-08-02T00:00:00', '2021-08-03T00:00:00')
['2021-08-03T00:00:00', '2021-08-04T00:00:00')
['2021-08-04T00:00:00', '2021-08-05T00:00:00')

这与我之前的问题 有点相关,但是由于查询范围内的时间戳在查询中的很多地方都用到了,所以我完全不知道该怎么做。

任何 help/direction 将不胜感激。

这应该让你开始:https://www.db-fiddle.com/f/qm4F7qqWZMrtXtMejimVJr/1

基本上,我所做的是预先准备带有 CTE 的范围,然后 select 从 table 表达式中使用原始查询的 CROSS JOIN LATERAL。接下来,我将所有出现的 20210803 替换为 lower(target_range),将 20210804 替换为 upper(target_range),然后添加 target_range 的 GROUP BY。请注意,只有那些与输入中至少一行重叠的范围才会出现在输出中;将交叉连接更改为 LEFT JOIN 以始终在输出中看到您的输入范围,即使值为 null。 (如果是这样,ON TRUE 适用于连接条件,因为您已经对内部子查询的 WHERE 进行了过滤。)