如何实现同一列的递归计算?

问题描述 投票:0回答:1

我有下表:

身份证 交易 金额 库存 价格
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(复制之前的平均值)

我尝试过以下方法:

  1. 使用起始值为 90 的列 (Average),并在另一列 (Average_f) 中运行计算。
    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
  1. 我也尝试过更新声明:
    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 中是否有一种方法可以单独计算每一行,或者有其他方法可以使用之前的平均值来计算平均值?

sql sql-server window-functions
1个回答
0
投票

如果是递归计算,为什么不实现呢?

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
© www.soinside.com 2019 - 2024. All rights reserved.