我的程序需要将一个金额传递到查询中以执行此类计算,但在我的例子中,它逐行循环并扣除正确的金额,我知道这不是一种有效的实现方式。所以我在这里寻求更好的方法。
PS:这只是我的草稿代码,很抱歉由于某些原因我无法发布完整的源代码。现在我重新构建了我的代码,使其更加完整和合理。
--- the amount column is just for reference.
insert into tbl1 (idx,amount,balance) values (1, 50, 50)
insert into tbl1 (idx,amount,balance) values (2, 30, 30)
insert into tbl1 (idx,amount,balance) values (3, 20, 20)
insert into tbl1 (idx,amount,balance) values (4, 50, 50)
insert into tbl1 (idx,amount,balance) values (5, 60, 60)
declare @total_value_to_deduct int
declare @cs_index int, @cs_balance int, @deduct_amount int
set @total_value_to_deduct = 130
declare csDeduct Cursor for select idx, balance from tbl1 where balance > 0
open csDeduct fetch next from csDeduct into @cs_index, @cs_balance
while @@FETCH_STATUS = 0 and @total_value_to_deduct > 0
begin
if @cs_balance >= @total_value_to_deduct
set @deduct_amount = @total_value_to_deduct
else
set @deduct_amount = @cs_balance
-- contine deduct row by row if the total_value_to_deduct is not 0
set @total_value_to_deduct = @total_value_to_deduct - @deduct_amount
update tbl1 set balance = balance - @deduct_amount where idx = @cs_index
fetch next from csDeduct into @cs_index, @cs_balance
end
close csDeduct
deallocate csDeduct
预期结果:
idx amount balance
1 50 0
2 30 0
3 20 0
4 50 20
5 60 60
非常感谢您的帮助。谢谢
最佳答案
修订版 1:我添加了第三个解决方案
第一个解决方案(SQL2005+;online query)
声明@tbl1 表 ( idx INT IDENTITY(2,2) 主键, 金额 INT NOT NULL, 余额 INT 不为空 );
INSERT INTO @tbl1 (amount,balance) VALUES (50, 50); INSERT INTO @tbl1 (amount,balance) VALUES (30, 30); INSERT INTO @tbl1 (amount,balance) VALUES (20, 20); INSERT INTO @tbl1 (amount,balance) VALUES (50, 50); INSERT INTO @tbl1 (amount,balance) VALUES (60, 60);
声明@total_value_to_deduct INT; SET @total_value_to_deduct = 130;
与 CteRowNumber 作为 ( 选择 *, ROW_NUMBER() OVER(ORDER BY idx) AS RowNum 来自@tbl1 ), Cte递归 作为 ( 选择 a.idx, a.数量, a.amount AS running_total, 案件 当 a.amount <= @total_value_to_deduct THEN 0 否则 a.amount - @total_value_to_deduct 结束为 new_balance, a.行号 FROM CteRowNumber a 其中 a.RowNum = 1 --AND a.amount < @total_value_to_deduct 联合所有 选择 crt.idx, crt.amount, crt.amount + prev.running_total AS running_total, 案件 当 crt.amount + prev.running_total <= @total_value_to_deduct THEN 0 当 prev.running_total < @total_value_to_deduct AND crt.amount + prev.running_total > @total_value_to_deduct THEN crt.amount + prev.running_total - @total_value_to_deduct ELSE crt.amount 结束为 new_balance, crt.RowNum 来自 CteRowNumber crt INNER JOIN CteRecursive prev ON crt.RowNum = prev.RowNum + 1 --WHERE prev.running_total < @total_value_to_deduct ) 更新@tbl1 设置余额 = b.new_balance 来自@tbl1a
方案二(SQL2012)
更新@tbl1 设置余额 = b.new_balance 来自@tbl1 内部联接 ( 选择 x.idx, SUM(x.amount) OVER(ORDER BY x.idx) AS running_total, 案件 当 SUM(x.amount) OVER(ORDER BY x.idx) <= @total_value_to_deduct THEN 0 当 SUM(x.amount) OVER(ORDER BY x.idx) - x.amount < @total_value_to_deduct --prev_running_total < @total_value_to_deduct AND SUM(x.amount) OVER(ORDER BY x.idx) > @total_value_to_deduct THEN SUM(x.amount) OVER(ORDER BY x.idx) - @total_value_to_deduct ELSE x.amount 结束为 new_balance 来自 @tbl1 x ) b ON a.idx = b.idx;
第三个解决方案 (SQ2000+) 使用 triangular join :
更新@tbl1 设置余额 = d.new_balance 来自 @tbl1 e 内部联接 ( 选择 c.idx, 案件 当 c.running_total <= @total_value_to_deduct THEN 0 当 c.running_total - c.amount < @total_value_to_deduct --prev_running_total < @total_value_to_deduct AND c.running_total > @total_value_to_deduct 然后 c.running_total - @total_value_to_deduct ELSE c.amount 结束为 new_balance 从 ( 选择 a.idx, a.数量, (SELECT SUM(b.amount) FROM @tbl1 b WHERE b.idx <= a.idx) AS running_total 来自@tbl1 ) C )d ON d.idx = e.idx;
关于sql - 在 T-SQL 中执行此类计算逻辑的最佳方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9938828/