减少一个表中的值,直到另一个表中的储备耗尽 - 递归?

时间:2009-10-14 08:06:31

标签: sql tsql dynamic recursion

我有两张桌子 - 让我们称之为dbo.ValuesToReduce和dbo.Reserve 第一个表(dbo.ValuesToReduce)中的数据是:

ValuesToReduceId | PartnerId | Value
-------------------------------------
1                | 1         | 53.15
2                | 2         | 601.98
3                | 1         | 91.05
4                | 2         | 44.56
5                | 3         | 19.11

第二个表(dbo.Reserve)看起来像这个

ReserveId | PartnerId | Value
-------------------------------
1         | 1         | -101.55
2         | 2         | -425.19
3         | 3         | -28.17

我需要做的是:使用后一个储备表更新ValuesToReduce表中的值,减少数量直到预留供应耗尽。这是运行脚本后我应该得到的:

ValuesToReduceId | PartnerId | Value
-------------------------------------
1                | 1         | 0.00
2                | 2         | 176.79
3                | 1         | 42.65
4                | 2         | 44.56
5                | 3         | 0.00


ReserveId | PartnerId | Value
-------------------------------
1         | 1         | 0.00
2         | 2         | 0.00
3         | 3         | -9.06

所以基本上,每个伙伴都有一个他可以消耗的“储备”,如果储备中还有东西,价值表中的值应该由合作伙伴相应减少。储备应按ValuesToReduceId提供的顺序并置。

对于PartnerId为1的合作伙伴,您可以看到他有足够的储备来将他的第一个值更新为0,并且还有一些剩下的可以将第二个值减少到该数量。

ID为2的合作伙伴有一个425.19的保留,并且该合作伙伴的值表中有两个条目,601.98和44.56,按顺序(通过ValuesToReduceId),所以我们只更新了第一个值,因为保留是两者都不够大。错误的方法是将第二个值更新为0.00,将第一个值更新为221.35。

ID为3的合作伙伴有足够的储备,因此在将其值更新为0后,他留下了-9.06

我尝试了递归cte的东西,但我似乎无法理解它。 希望我能够清楚地描述这个问题。

1 个答案:

答案 0 :(得分:1)

据我所知,你不能在一个select语句中更新两个表。

但是您可以使用WHILE循环在SQL中执行此操作。搜索第一个交易,然后执行,直到没有可能的交易。

declare @valid int
declare @resid int
declare @val float
while 1 = 1
    begin

    select top 1 
      @resid = r.ReserveId
    , @valid = v.ValuesToReduceId
    , @val = CASE WHEN -r.Value > v.Value THEN v.Value ELSE -r.Value END
    from ValuesToReduce v
    inner join Reserves r on r.PartnerId = v.PartnerId
    where r.Value < 0 and v.Value > 0
    order by r.ReserveId

    if @@rowcount = 0
        break

    update ValuesToReduce 
    set Value = Value - @val 
    where ValuesToReduceId = @valid

    update Reserves 
    set Value = Value + @val 
    where ReserveId = @resid
    end

以下是创建测试表的代码:

create table ValuesToReduce (
    ValuesToReduceId int,
    PartnerId int,
    Value float
)

insert into ValuesToReduce values (1,1,53.15)
insert into ValuesToReduce values (2,2,601.98)
insert into ValuesToReduce values (3,1,91.05)
insert into ValuesToReduce values (4,2,44.56)
insert into ValuesToReduce values (5,3,19.11)

create table Reserves (
    ReserveId int,
    PartnerId int,
    Value float
)

insert into Reserves values  (1,1,-101.55)
insert into Reserves values (2,2,-425.19)
insert into Reserves values (3,3,-28.17)