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

Sql 减少一个表中的值,直到储量在另一个表中耗尽-递归?,sql,tsql,dynamic,recursion,Sql,Tsql,Dynamic,Recursion,我有两个表——我们把它们称为dbo.ValuesToReduce和dbo.Reserve 第一个表(dbo.ValuesToReduce)中的数据是: 第二个表(dbo.Reserve)如下所示 ReserveId | PartnerId | Value ------------------------------- 1 | 1 | -101.55 2 | 2 | -425.19 3 | 3 | -2

我有两个表——我们把它们称为dbo.ValuesToReduce和dbo.Reserve 第一个表(dbo.ValuesToReduce)中的数据是:

第二个表(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尝试了一些东西,但我似乎无法理解它。
希望我对问题描述得足够清楚。

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

但您可以在SQL中使用WHILE循环来实现这一点。搜索第一笔交易,然后执行,直到没有可能的交易

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

为什么要使用cte?看起来VB和SQL的结合将产生一个更简单的解决方案。VB可以做循环,if-then-else逻辑,SQL可以选择和更新记录?我最终使用了类似的东西,明天,我将尝试使用仅快进游标对其进行优化,因为如果我能在ValuesToReduce表中获得正确的结果,我实际上不需要在第一次运行时更改Reserves表中的值(注意Reserves中的值减少,并跟踪剩余的量)。我还在更新中使用对标量函数的调用来刺激解决方案,但我想我将继续讨论这个问题。明天我还会再处理一点递归,如果我能想出一些像样的方法,我会告诉你的。谢谢
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)