我有下表:
身份证 | 交易 | 金额 | 库存 | 价格 |
---|---|---|---|---|
1 | 空 | 空 | 11 | 空 |
2 | 销售 | -1 | 10 | 100 |
3 | 购买 | 2 | 12 | 102 |
4 | 销售 | -2 | 10 | 103 |
第一行是起始金额,接下来的三行显示更改库存的交易。我需要根据购买情况计算新的运行平均价格,并根据以下公式复制当前平均价格(如果发生销售):
If Transaction = NULL (i.e. starting line) then Average = 90;
If Transaction = 'Sale' then Average = lag(Average) (i.e. whatever is the latest calculated average);
If transaction = 'Purchase' then ((Inventory - Amount) * lag(Average)
+ Amount * Price)
/ Inventory
排序顺序是 ID 列升序。
问题是由滞后(平均)造成的,因为每个计算步骤都需要前一行是更新值,即计算必须逐行运行和更新。
结果表应该如下所示:
身份证 | 交易 | 金额 | 库存 | 价格 | 平均 |
---|---|---|---|---|---|
1 | 空 | 空 | 11 | 空 | 90 |
2 | 销售 | -1 | 10 | 100 | 90 |
3 | 购买 | 2 | 12 | 102 | 92 |
4 | 销售 | -2 | 10 | 103 | 92 |
计算:
ID 1 --> 90(起始值)
ID 2 --> 90(复制之前的平均值)
ID 3 --> 92 = ((12 - 2) * 90 + (2 * 102)) / 12
ID 4 --> 92(复制之前的平均值)
我尝试过以下方法:
Select *,
case when [transaction] is null then Average
when [transaction] = 'Sale' then lag(Average) over (order by ID)
when [transaction] = 'Purchase'
then (((Inventory - Amount) * lag(Average) over (order by ID))
+ (Amount * Price)) / Inventory
end as Average_f
from table
没成功:
身份证 | 交易 | 金额 | 库存 | 价格 | 平均 | 平均_f |
---|---|---|---|---|---|---|
1 | 空 | 空 | 11 | 空 | 90 | 90 |
2 | 销售 | -1 | 10 | 100 | 空 | 90 |
3 | 购买 | 2 | 12 | 102 | 空 | 空 |
4 | 销售 | -2 | 10 | 103 | 空 | 空 |
update table
set average = case when [transaction] is null then Average
when [transaction] = 'Purchase'
then (((Inventory - Amount) * (select lag(Average) over (order by ID)
from table t
where t.ID = table.ID))
+ (Amount * Price)) / Inventory
when [transaction] = 'Sale' then (select lag(Average) over (order by ID)
from table t
where t.ID = table.ID)
end
也不起作用:
身份证 | 交易 | 金额 | 库存 | 价格 | 平均 |
---|---|---|---|---|---|
1 | 空 | 空 | 11 | 空 | 90 |
2 | 销售 | -1 | 10 | 100 | 空 |
3 | 购买 | 2 | 12 | 102 | 空 |
4 | 销售 | -2 | 10 | 103 | 空 |
SQL 中是否有一种方法可以单独计算每一行,或者有其他方法可以使用之前的平均值来计算平均值?
如果是递归计算,为什么不实现呢?
with cte(ID, Transaction, Amount, Inventory, Price, Average) as (
select d.*, 90
from data d where d.id = 1
union all
select d.ID, d.Transaction, d.Amount, d.Inventory, d.Price,
case d.Transaction
when 'Sale' then c.Average
when 'Purchase' then
((d.Inventory - d.Amount) * c.Average
+ d.Amount * d.Price) / d.Inventory
else
90
end
from cte c
join data d on d.id = c.id + 1
)
select * from cte
;
1 11 90
2 Sale -1 10 100 90
3 Purchase 2 12 102 92
4 Sale -2 10 103 92