Sql 减少一个表中的值,直到储量在另一个表中耗尽-递归?
我有两个表——我们把它们称为dbo.ValuesToReduce和dbo.Reserve 第一个表(dbo.ValuesToReduce)中的数据是: 第二个表(dbo.Reserve)如下所示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
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)