SQL 中每个分区的 last_value 和窗口函数的总和
Posted
技术标签:
【中文标题】SQL 中每个分区的 last_value 和窗口函数的总和【英文标题】:Sum of last_value of each partition in SQL with window functions 【发布时间】:2021-02-28 05:58:57 【问题描述】:我有一个表,用于存储每个实体在任何时间点使用的总磁盘数。我想找到一个时间段内使用的峰值磁盘。 例如,数据看起来像
注意:时间戳是具有秒精度的实际时间戳,为简洁起见,我将其设置为上午 10 点等
timestamp | entity_id | disk_used
---------------------------------
9am | 1 | 10
10am | 2 | 20
11am | 2 | 15
12am | 1 | 12
在本例中,使用的最大磁盘数为 30(实体 1 为 10,实体 2 为 20)。
我尝试了很多方法。
-
(每个实体的最大值)的总和不起作用,因为它会给出结果 20 + 12 = 32。但在实体 1 增加其大小之前,实体 2 减小了大小,因此峰值磁盘使用量为 30 .
我尝试使用窗口函数找到每个实体的last_value之和
select timestamp, entity_id,
disk_used,
sum(last_value(disk_used) over(
partition by entity_id order by timestamp)
) sum_of_last
正在尝试生成,因此我可以将其最大化,
timestamp | entity_id | disk_used | sum_of_last
-----------------------------------------------
9am | 1 | 10 | 10
10am | 2 | 20 | 30
11am | 2 | 15 | 25 // (10 + 15)
12am | 1 | 12 | 27 // (12 + 15)
但是,该查询不起作用,因为我们无法通过 ISO 标准 SQL 2003 中的窗口函数进行聚合。我正在使用 Amazon timestream db。查询引擎与 ISO 标准 SQL 2003 兼容。
-- 重新表述相同的问题,在每个时间戳我们都有数据点,用于该时刻使用的总磁盘。 要找到当时使用的总磁盘总量,请将每个实体的最后一个值相加。
有没有一种有效的方法来计算这个?
【问题讨论】:
(1) SQL 2003?请标记您正在使用的数据库。 (2) 你想要什么结果? 我们使用 amazon timestream,它是来自 amazon 的新时间序列数据库。我听到的查询与SQL 2003兼容。(并且有一些附加功能) 。 .也许引用的是 ISO 标准 SQL 2003。如果没有引用,只是“sql 2003”似乎很尴尬。 【参考方案1】:如果你只有两个实体,你可以这样做:
select t.*,
(last_value(case when entity_id = 1 then disk_used end ignore nulls) over (order by time) +
last_value(case when entity_id = 2 then disk_used end ignore nulls) over (order by time)
) as total
from t;
对所有实体进行概括的一种方法是每次为每个实体生成一行,估算值并聚合:
select ti.time, e.entity_id,
last_value(disk_used ignore nulls) over (partition by e.entity_id order by t.time) as imputed_disk_used
from (select distinct time from t) ti cross join
(select distinct entity_id from t) e left join
t
on ti.time = t.time and e.entity_id = t.entity_id;
然后就可以聚合了:
select time, sum(imputed_disk_used)
from (select ti.time, e.entity_id,
last_value(disk_used ignore nulls) over (partition by e.entity_id order by t.time) as imputed_disk_used
from (select distinct time from t) ti cross join
(select distinct entity_id from t) e left join
t
on ti.time = t.time and e.entity_id = t.entity_id
) te
group by time;
但是,这给出了 per time 而不是 per time 和 entity_id
的值。
【讨论】:
这不起作用,因为在我给出的示例中,它几乎等于使用的磁盘。 对不起,实体的数量可能有几十万。我给出了简化的示例来重现 *** 通常推荐的问题。【参考方案2】:我要查找某个时间段内使用的峰值磁盘
您可以使用两个级别的聚合:
select max(sum_disk_used)
from (
select time, sum(disk_used) as sum_disk_used
from mytable
group by time
) t
子查询计算每个时间点的总disk_used
,然后外部查询只获取峰值。
如果您的数据库支持某种limit
子句,这可以简化:
select time, sum(disk_used) as sum_disk_used
from mytable
group by time
order by sum_disk_used limit 1
要过滤给定的时间段,您通常会在子查询中添加 where
子句。
【讨论】:
这行不通,我表中的时间戳是一个时间戳,为简洁起见,我将其设为上午 10 点、上午 11 点等。 我想找出一整天的磁盘使用高峰。 @JackDaniels:time
列的数据类型对我提供的查询没有影响。请解释您得到的结果有什么问题。
我想我会改变这个例子,假设第一行的时间是上午 9 点。在这种情况下,您的示例将给出 20 的结果,而不是我们想要的 30。以上是关于SQL 中每个分区的 last_value 和窗口函数的总和的主要内容,如果未能解决你的问题,请参考以下文章
SQL查询获取分区里最大和最小值_first_value/last_value
LAST_VALUE with IF statement inside not backfill it's partition --> 在选择每个分区的第一行时丢失最后一个值(BigQuery/
窗口分析函数19_Mysql查询窗口函数里第一个最后一个第N个元素的值值案例详解(FIRST_VALUE LAST_VALUE NVH_VALUE)