我的 SQL 生锈了。 我有一个像这样的数据框/表(部分显示,这只是一个示例,不是真实的数据):
+--------------------+-----+---+
| timestamp|value| id|
+--------------------+-----+---+
|2024-10-05 20:38:...| 67| 0|
|2024-10-05 19:38:...| 14| 1|
|2024-10-05 18:38:...| 80| 2|
|2024-10-05 17:38:...| 6| 3|
+--------------------+-----+---+
用简单的英语来说,我想做的是:假设
id
位于第 0 行。我想要获得一个数据结果集,这样对于第 0 行中的 id
,我返回所有数据的总和在第 0 行中的 value
之前 3 小时的所有行的第 timestamp
列中,并包括第 0 行的 value
。然后,我想对所有行(0 到 n
)执行此操作(其中 n
行可能很大,约为数亿)。
所以,我的输出将如下所示(稍微截断):
+--------------------+-----+---+
| timestamp|sum | id|
+--------------------+-----+---+
|2024-10-05 20:38:...| 167| 0| /* this result is the `value` of the id in row 0, plus the three hours' of previous data */
|2024-10-05 19:38:...| 100| 1| /* this would be more than 100 with the full dataset, etc. */
|2024-10-05 18:38:...| 86| 2|
+--------------------+-----+---+ /* etc etc */
我确定已经有人问过这个问题或变体,但我做了大量研究,但似乎找不到这个问题。 更具体地说,我正在使用 Spark DataFrames,但普通 SQL 也可以。
在 SQLite 中你可以这样做
SELECT
d.timestamp,
d.value,
d.id,
(
SELECT
SUM(di.value)
FROM data di
WHERE
di.timestamp BETWEEN datetime(d.timestamp, '-3 hours') AND d.timestamp
) AS sum
FROM data d;
不太熟悉 Spark,但谷歌搜索 Spark DataFrames 和“窗口函数”会返回有希望的结果
您的帮手是窗口函数。我不熟悉 Apache Spark,但关于文档(https://spark.apache.org/docs/latest/sql-ref-syntax-qry-select-window.html)它应该在这个领域工作就像 Postgresql 一样。
简而言之,窗口函数执行某种数据聚合,无需对行进行分组,而是使用一个计算操作的窗口。如果您正在使用例如sum,然后使用提供的 order by,您将得到一个运行总和,或者在您的情况下得到一个逆运行总和。
select
ts, value, id,
sum(value) over (order by id desc) as sum
from dataframe order by id;
were
sum(value) over (order by id desc)
是一个窗口函数并提供以下结果:
ts | 价值 | id | 总和 |
---|---|---|---|
2024-10-05 20:38:00 | 67 | 0 | 167 |
2024-10-05 19:38:00 | 14 | 1 | 100 |
2024-10-05 18:38:00 | 80 | 2 | 86 |
2024-10-05 17:38:00 | 6 | 3 | 6 |