PostgreSQL中的条件累积平均
我有一个简单的表,它是:PostgreSQL中的条件累积平均,sql,postgresql,Sql,Postgresql,我有一个简单的表,它是: DROP TABLE IF EXISTS running_averages; CREATE TABLE running_averages ( avg_id SERIAL NOT NULL PRIMARY KEY, num1 integer, num2 integer DEFAULT 0
DROP TABLE IF EXISTS running_averages;
CREATE TABLE running_averages
(
avg_id SERIAL NOT NULL PRIMARY KEY,
num1 integer,
num2 integer DEFAULT 0
);
INSERT INTO running_averages(num1, num2)
SELECT 100, 100 UNION ALL
SELECT 200, 175 UNION ALL
SELECT -400, NULL UNION ALL
SELECT 300, 200 UNION ALL
SELECT -100, NULL;
在上表中,如果num1列为负值,则应使用前一行的累积平均值更新num2列。我目前的查询是:
SELECT *,
num1 * num2 AS current_total,
SUM(num1 * num2) OVER(order by avg_id) AS cumulative_sum,
SUM(num1) OVER(order by avg_id) AS culmulative_num1,
CASE WHEN num1 > 0 THEN
SUM(num1 * num2) OVER(order by avg_id)
/
SUM(num1) OVER(order by avg_id)
ELSE
0
END AS cumulative_average
FROM running_averages;
结果是:
avg_id num1 num2 current_total cumulative_sum cumulative_num1 cumulative_average
1 100 100 10,000 10,000 100 100
2 200 175 35,000 45,000 300 150
3 -400 NULL 45,00 -100 0
4 300 200 60,000 105,000 200 525
5 -100 NULL 105,000 100 0
如果当前行的num1列为负数,我无法找出将前一行的累积平均值带入的方法。预期输出应为:
avg_id num1 num2 current_total cumulative_sum cumulative_num1 cumulative_average
1 100 100 10,000 10,000 100 100
2 200 175 35,000 45,000 300 150
3 -400 150 -60,000 -15,00 -100 150
4 300 200 60,000 45,000 200 225
5 -100 225 -22,500 22,500 100 225
在这种情况下,如何获取最后一行的列的值
编辑:
我编辑了上面的SQL脚本。我很喜欢他回答问题的方式。但遗憾的是,根据脚本更改,它会产生错误的结果:
avg_id num1 num2 new_num2
1 100 100 100
2 200 175 175
3 -400 150 150 (Correct)
4 300 200 200
5 -100 225 50 (Incorrect)
编辑2
我还测试了的答案,它也产生了错误的结果:
avg_id num1 num2 current_total cumulative_sum cumulative_num1 cumulative_average
1 100 100 10,000 10,000 100 100
2 200 175 35,000 45,000 300 150
3 -400 150 (Correct) -60,000 -15,00 -100 150
4 300 200 60,000 45,000 200 225
5 -100 175 (Incorrect) -17,500 27,500 100 275
编辑3
我已经接受了Multisync的更新答案,因为它产生了正确的结果。我还想知道如何改进这样的查询,因为我们有很多聚合和窗口函数。关于这个主题的任何参考都会很有帮助。我只能想到一个递归查询:
with recursive tmp (avg_id, num1, num2, sum_m, sum_num1, last_id) as (
select avg_id, num1, num2, num1 * num2, num1, avg_id
from running_averages where avg_id = 1
union all
select r.avg_id, r.num1,
case when r.num1 < 0 then t.sum_m / t.sum_num1 else r.num2 end,
t.sum_m + case when r.num1 < 0 then t.sum_m / t.sum_num1 else r.num2 end * r.num1,
t.sum_num1 + r.num1,
r.avg_id
from running_averages r join tmp t on r.avg_id = t.last_id + 1
)
select avg_id, num1, num2,
num1 * num2 AS current_total,
SUM(num1 * num2) OVER(order by avg_id) AS cumulative_sum,
SUM(num1) OVER(order by avg_id) AS culmulative_num1,
SUM(num1 * num2) OVER(order by avg_id)
/ SUM(num1) OVER(order by avg_id) AS cumulative_average
from tmp;
avg_id必须包含consequentive数字。您可以改为使用row_数字,我没有使用它来简化
num2在计算过程中发生了变化,这就是为什么我想不出任何东西,而上一步的递归查询输出就是下一步的输入
在上表中,num2列应更新为
如果列num1为a,则上一行的累积平均值
负值
这不应该太难:
select ra.*,
(case when num1 >= 0 then num2
else avg(num1) over (order by avg_id rows between unbounded preceding and 1 preceding)
end) as new_num2
from running_averages ra;
我想你可以使用new_num2来完成剩下的计算。我已经编辑了这个问题,因为当引入一个新的负行时,它产生了一个错误的结果。你能看看这个吗在我在真实的表中测试后,这也会产生错误的结果。我已经编辑了关于为什么显示错误结果的问题。@Nancy一天前它根据您的问题生成了结果,我深表歉意。在试图简化数据库脚本时,我错过了它@南希:对不起,我检查了我的答案——有一个错误。我更新了我的答案。事实上我自己想出了一个解决办法。但是这个比我的好一千倍P