基于单个分组事件构建具有累计和的时间序列

首先,我需要强调的是,我对SQL非常陌生,当前状态是在堆栈溢出的帮助下实现的.

我有一个表格,其中包含发生的不同类型的事件.我想将这些数据转换成时间序列,填补事件之间的时间间隔,并累积不同类型事件的数字.

因此,这一切都是为了从单个事件创建时间序列,并计算跨事件组的运行/累积总和

下面是源数据的示例:

资料来源:

event_timestamp    type  value
01.01.2023 10:00   1     10
03.01.2023 10:00   2     10
05.01.2023 10:00   2     10
07.01.2023 10:00   1     10

预期结果:

event_timestamp    type value cumulative_sum
01.01.2023 10:00   1    10    10
02.01.2023 10:00   1    0     10
03.01.2023 10:00   1    0     10
03.01.2023 10:00   2    10    10
04.01.2023 10:00   1    0     10
04.01.2023 10:00   2    0     10
05.01.2023 10:00   1    0     10
05.01.2023 10:00   2    10    20
06.01.2023 10:00   1    0     10
06.01.2023 10:00   2    0     20
07.01.2023 10:00   1    10    20
07.01.2023 10:00   2    0     20

我达到了一个点,在那里我可以创建以下内容(仅限于单个事件类型):

time               type value cumulative_sum
01.01.2023 10:00   1    10    10
02.01.2023 10:00   1    0     10
03.01.2023 10:00   1    10    20
04.01.2023 10:00   1    0     20
05.01.2023 10:00   1    0     20
06.01.2023 10:00   1    0     20
07.01.2023 10:00   1    0     20

使用以下SQL语句(PostgreSQL):

SELECT  
generate_series AS timestamp,
-- hard coded event type below
COALESCE(events.type, 1) AS type,
COALESCE(events.value, 0) AS value,
COALESCE(SUM(td.value) OVER (ORDER BY generate_series), 0) AS cumulative_sum  
FROM  
generate_series('2023-01-01'::timestamp, '2023-01-07'::timestamp, '1 day') AS generate_series  
LEFT JOIN  
-- hard coded event type below
events ON generate_series = events.event_timestamp AND event.type = 1 
ORDER BY  
generate_series;

现在我在问,我是否应该try 找到以更好的方式执行所有操作的SQL语句(不知道如何执行),或者是否应该使用一个python脚本来针对每个事件类型运行此语句,然后将数据插入到表中.

问题摘要:

  • 使用SQL和Python的组合来进行这样的计算是否可取?
  • 把时间系列的创作和累计总和分开会不会更好?
  • 如果建议使用纯SQL方式,考虑到组,如何做到这一点

推荐答案

你已经很接近了.您所需要的就是为每种类型创建系列.交叉联接可以很容易地做到这一点.

看看这个:

SELECT generate_series AS timestamp
     , etypes.type
     , COALESCE(events.value, 0) AS value
     , COALESCE(SUM(events.value) OVER (PARTITION BY etypes.type ORDER BY generate_series), 0) AS cumulative_sum
  FROM generate_series('2023-01-01'::timestamp, '2023-01-07'::timestamp, '1 day') AS generate_series
  CROSS JOIN (SELECT DISTINCT type FROM events) AS etypes
  LEFT JOIN events ON generate_series = events.event_timestamp AND events.type = etypes.type
 ORDER BY generate_series, etypes.type
;

在给定范围内没有数据的情况下,结果如下:

timestamp type value cumulative_sum
2023-01-01 00:00:00 1 0 0
2023-01-01 00:00:00 3 0 0
2023-01-02 00:00:00 1 0 0
2023-01-02 00:00:00 3 0 0
2023-01-03 00:00:00 1 0 0
2023-01-03 00:00:00 3 0 0
2023-01-04 00:00:00 1 0 0
2023-01-04 00:00:00 3 0 0
2023-01-05 00:00:00 1 0 0
2023-01-05 00:00:00 3 0 0
2023-01-06 00:00:00 1 0 0
2023-01-06 00:00:00 3 0 0
2023-01-07 00:00:00 1 0 0
2023-01-07 00:00:00 3 0 0

Test case (with a little data added)

您还可以基于每种类型的开始和结束,为该类型创建具有不同范围的系列.

下面是一个这样的例子:

SELECT generate_series AS timestamp
     , etypes.type
     , COALESCE(events.value, 0) AS value
     , COALESCE(SUM(events.value) OVER (PARTITION BY etypes.type ORDER BY generate_series), 0) AS cumulative_sum
  FROM (SELECT type
             , MIN(event_timestamp) AS mints
             , MAX(event_timestamp) AS maxts
          FROM events
         GROUP BY type
       ) AS etypes
  JOIN LATERAL (SELECT generate_series(mints, maxts, '1 day') AS generate_series) AS gs ON 1 = 1
  LEFT JOIN events ON generate_series = events.event_timestamp AND events.type = etypes.type
 ORDER BY generate_series, etypes.type
;

您的数据带来的结果:

timestamp type value cumulative_sum
2023-01-01 00:00:00 1 10 10
2023-01-02 00:00:00 1 0 10
2023-01-03 00:00:00 1 0 10
2023-01-03 00:00:00 2 10 10
2023-01-04 00:00:00 1 0 10
2023-01-04 00:00:00 2 0 10
2023-01-05 00:00:00 1 0 10
2023-01-05 00:00:00 2 10 20
2023-01-06 00:00:00 1 0 10
2023-01-07 00:00:00 1 10 20

Sql相关问答推荐

GROUP BY和GROUP_CONCAT用于计算比赛排名

基于前面行的值:当x&>2时重复1,当连续3行x=0时则重复0

在SQL中使用类别值将行转置为列

PostgreSQL中的合并命令是原子的,还是需要一些类似于SQL Server版本的内容?

防止ActiveRecord迁移在db/structure.sql中进行巨大更改

使用列表作为参数进行 Select ,如果为空,则在PostgreSQL中不使用参数进行 Select

根据最大值为字母数字大小写分配数值

Oracle 23c ROUND,数据类型为DATE

在Power Bi中将SQL代码转换为DAX

将伪数据插入Postgres表

需要使用SQLite查询进行一些奇怪的时间转换

SAS proc freq 或 proc sql 获取数据子集和整个数据的频率

使用 union 的有序结果获取行数

GRAFANA 数据库查询错误:pq:列名称不存在

对于小数据集,EF / SQL 语句花费的时间太长

获取多个开始-结束时间戳集之间经过的时间

如何使用 join 和 where 子句从另一表中仅删除一个表中的值

按所选的值将记录分组到不同的列中

SQL Select 最大并获取列名

遍历数据,计算每个月最后三天的总和