Postgres 移动平均线
Posted
技术标签:
【中文标题】Postgres 移动平均线【英文标题】:Postgres moving average 【发布时间】:2021-01-18 05:26:31 【问题描述】:正在尝试验证我的移动平均计算...但是我得到了两个不同的值,我希望每个查询都返回相同的值:
select sum(a.processing) / 50 as myMean
from (select created, processing
from myTable
where name = 'stack'
order by created desc
limit 50) a
union
select b.*
from (select AVG(processing)
filter (where name = 'stack')
OVER (ORDER BY created desc ROWS BETWEEN 49 PRECEDING AND CURRENT ROW)
from myTable
where name = 'stack'
order by created desc
limit 1) b
第一个查询我得到处理值的总和,然后除以 N(这里是 50),第二个查询我尝试使用窗口函数来实现同样的事情 - 获得最后 50 个的平均处理值name = stack 的行。
【问题讨论】:
有什么问题?这似乎完全符合你的描述?使用一些示例数据并期望输出会更容易理解您想要什么。 @T.Peter 我得到两个不同的值,我希望这些值是相同的 【参考方案1】:ROWS BETWEEN 50 PRECEDING AND CURRENT ROW
子句将处理 51 行(前 50 行加上当前行)。
没有窗口函数的第一个查询将处理 50 行。
另外,你的OVER
子句应该是FOLLOWING
,而不是PRECEDING
:
OVER (ORDER BY created desc ROWS BETWEEN CURRENT ROW AND 49 FOLLOWING ROW)
现在的写法,它只显示第一行的平均值,即第一行的值,而不是前50行的平均值。
【讨论】:
改成四十九了,每次查询还是得到不同的结果,会更新问题 @NimChimpsky,OVER
子句应该有FOLLOWING
,而不是PRECEDING
框架。问题中的样本数据和预期结果通常有助于获得良好的正确答案。
@NimChimpsky,你可以玩简单的例子here。尝试不同的变体,你会看到它是如何工作的。这就是为什么拥有一些示例数据很有用的原因 - 您可以快速检查查询是否产生了预期的结果。【参考方案2】:
我认为OP误解的部分是Windows函数over
中的order by
:
select b.*
from (select AVG(processing)
filter (where name = 'stack') --filter do nothing here
OVER (ORDER BY created desc ROWS BETWEEN 50 PRECEDING AND CURRENT ROW)
from myTable
where name = 'stack' --where clause already filter the name
order by created desc
limit 1) b
让我们稍微修改一下以显示order by
在此查询中实际执行的操作。
select b.*
from (select AVG(processing)
OVER (ORDER BY created desc ROWS BETWEEN 50 PRECEDING AND CURRENT ROW)
from myTable
where name = 'stack'
order by created desc
) b --remove limit
带有伪example
伪表:
| processing | created | name |
|------------|---------|------|
| 6 | 6 | a |
| 5 | 5 | a |
| 4 | 4 | a |
| 3 | 3 | a |
| 2 | 2 | a |
| 1 | 1 | a |
输出:
| avg | path |
|-----|-----------|
| 6 |6 |
| 5.5 |6+5 |
| 5 |6+5+4 |
| 4.5 |6+5+4+3 |
| 4 |6+5+4+3+2 |
| 3.5 |6+5+4+3+2+1|
如您所见,没有limit
订单将尝试平均当前行和前面的行(在本例中为前面的 50 行)。
但是当您在查询中添加limit 1
时,它只会从输出中返回第一行,因此 OP 只会将第一行视为输出,这会使 OP 对不同的结果感到困惑。
TL;DR :
查询的第二部分基本上返回第一行结果(排序后),这是没有意义的,因为一个条目的平均值是……没有意义的。
这里是MSDN 以便更好地检查。
顺便说一句,Sum(col) / n
是获取平均值的危险方法,如果将列数据存储为整数,您将得到一个非常不准确的结果,例如,如果真正的平均值是 3.5
,您将得到 3
。如果平均是你的目标,你应该远离使用正确的函数avg()
。
【讨论】:
这是不正确的,当我指定 postgres 时,您还链接到 msdn 链接到 msdn 是一个糟糕的问题,但 postgres 聚合函数与 windows 函数是相同的。它们基本上是一样的。 你是什么意思不正确,你的查询做了我回答的事情,你使用over
完全错误,我试图指出这一点。
极限并不像你想象的那样
限制按照我的想法做,唯一要做的就是指定要处理的行数...limit 1
= 第一行,limit 2
= 第一行和第二行... 以上是关于Postgres 移动平均线的主要内容,如果未能解决你的问题,请参考以下文章
在 Postgres 中,如何平均每个用户的最新 5 个分数?