sql 中的动态滚动平均值
dynamic rolling average in sql
希望我能解释清楚
我正在尝试计算滚动平均值,但前面的行数可变,具体取决于另一列的滚动总和。
或者换句话说,我想计算 b 列的最近平均值,相对于 a 列总和至少为 X
的前几行
示例数据:
CREATE TEMP TABLE t (ts timestamp NOT NULL, a int, b int);
INSERT INTO t VALUES
('20200929 11:00',1,50)
,('20200929 12:00',3,25)
,('20200929 13:00',1,20)
,('20200929 14:00',1,19)
,('20200929 15:00',2,25)
,('20200929 16:00',1,22)
,('20200929 17:00',3,19)
期望的结果,X = 3:
ts a b row_from row_to average_b
2020-09-29 11:00 1 50 NULL NULL NULL
2020-09-29 12:00 3 25 1 1 50
2020-09-29 13:00 1 20 2 2 25
2020-09-29 14:00 1 19 2 3 22.5
2020-09-29 15:00 2 25 2 4 21.333
2020-09-29 16:00 1 22 4 5 22.5
2020-09-29 17:00 3 19 5 6 23.5
我没有计算当前行的 a 值,因此 row_to 始终是前一行。
第三行只需要第2行
第四行需要第 2 行和第 3 行,因为第 2 行本身不是 >=3。我不介意超过 X 值。
我可以计算可变行数的平均值,但我不知道如何计算所需的 row_from。
我想这在 python 中很容易,但是在 TSQL 中是否有基于集合的方法来做到这一点?
我正在使用 PostgreSQL 10.5,但也可以使用 SQLServer 2019
我想不出不用递归怎么做。
除了 16:00
条目 ((19 + 25)/2 = 22
) 的算术错误外,这会产生您想要的输出:
with recursive nums as (
select *,
row_number() over (order by ts) as rn
from t
), stoprns as (
select *, rn as row_to, a as runsum
from nums
union all
select s.ts, s.a, s.b, n.rn, s.row_to, s.runsum + n.a
from stoprns s
join nums n
on n.rn = s.rn - 1
and s.runsum < 3
), ranges as(
select n.rn, n.ts, n.a, n.b,
min(s.rn) as row_from,
s.row_to
from nums n
left join stoprns s
on s.row_to = n.rn - 1
group by s.row_to, n.rn, n.ts, n.a, n.b
)
select *,
(select avg(b) from nums where rn between row_from and row_to) as average_b
from ranges
group by rn, ts, a, b, row_from, row_to
order by rn
;
根据您 table 的大小,这可能不可行,performance-wise。
希望我能解释清楚
我正在尝试计算滚动平均值,但前面的行数可变,具体取决于另一列的滚动总和。 或者换句话说,我想计算 b 列的最近平均值,相对于 a 列总和至少为 X
的前几行示例数据:
CREATE TEMP TABLE t (ts timestamp NOT NULL, a int, b int);
INSERT INTO t VALUES
('20200929 11:00',1,50)
,('20200929 12:00',3,25)
,('20200929 13:00',1,20)
,('20200929 14:00',1,19)
,('20200929 15:00',2,25)
,('20200929 16:00',1,22)
,('20200929 17:00',3,19)
期望的结果,X = 3:
ts a b row_from row_to average_b
2020-09-29 11:00 1 50 NULL NULL NULL
2020-09-29 12:00 3 25 1 1 50
2020-09-29 13:00 1 20 2 2 25
2020-09-29 14:00 1 19 2 3 22.5
2020-09-29 15:00 2 25 2 4 21.333
2020-09-29 16:00 1 22 4 5 22.5
2020-09-29 17:00 3 19 5 6 23.5
我没有计算当前行的 a 值,因此 row_to 始终是前一行。
第三行只需要第2行
第四行需要第 2 行和第 3 行,因为第 2 行本身不是 >=3。我不介意超过 X 值。
我可以计算可变行数的平均值,但我不知道如何计算所需的 row_from。 我想这在 python 中很容易,但是在 TSQL 中是否有基于集合的方法来做到这一点?
我正在使用 PostgreSQL 10.5,但也可以使用 SQLServer 2019
我想不出不用递归怎么做。
除了 16:00
条目 ((19 + 25)/2 = 22
) 的算术错误外,这会产生您想要的输出:
with recursive nums as (
select *,
row_number() over (order by ts) as rn
from t
), stoprns as (
select *, rn as row_to, a as runsum
from nums
union all
select s.ts, s.a, s.b, n.rn, s.row_to, s.runsum + n.a
from stoprns s
join nums n
on n.rn = s.rn - 1
and s.runsum < 3
), ranges as(
select n.rn, n.ts, n.a, n.b,
min(s.rn) as row_from,
s.row_to
from nums n
left join stoprns s
on s.row_to = n.rn - 1
group by s.row_to, n.rn, n.ts, n.a, n.b
)
select *,
(select avg(b) from nums where rn between row_from and row_to) as average_b
from ranges
group by rn, ts, a, b, row_from, row_to
order by rn
;
根据您 table 的大小,这可能不可行,performance-wise。