修改 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:00
到 2021-08-04T00:00:00
)
- 对于与
the range
重叠的每个事件
- Trim
order_dates
的 Lower 和 Upper 时间戳值到 the range
的边界
- 将每个适用事件的剩余持续时间乘以
event.flow
值
- 对最终单值输出的所有相乘值求和
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 进行了过滤。)
我对 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:00
到 2021-08-04T00:00:00
)
- 对于与
the range
重叠的每个事件
- Trim
order_dates
的 Lower 和 Upper 时间戳值到the range
的边界
- 将每个适用事件的剩余持续时间乘以
event.flow
值 - 对最终单值输出的所有相乘值求和
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 withinthe 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 进行了过滤。)