有没有办法应用行更新而不循环

时间:2019-04-13 13:11:30

标签: sql tsql

我想用我拥有的不同积分来支付不同的发票。

drop table #InvoicesWithBalances
drop table #AvailableCredits
create table #InvoicesWithBalances
(
InvoiceKey decimal(18,0) not null,
APBalance decimal(18,6) null,
BalanceAfterCreditApplied decimal(18,6) null,

)
create table #AvailableCredits
(
credit_id int identity(1,1),
StartingBalance decimal(18,6) null,
CurrentBalance decimal(18,6) null,

)

insert into #InvoicesWithBalances values (5452, 13744.080000, 13744.080000)
insert into #InvoicesWithBalances values (7056, 13744.080000, 13744.080000)
insert into #InvoicesWithBalances values (7438, 500.000000, 500.000000 )
insert into #AvailableCredits values ( -13744.080000, -13744.080000)
insert into #AvailableCredits values ( -13700.080000, -13700.080000)
insert into #AvailableCredits values ( -500.000000, -500.000000)
insert into #AvailableCredits values ( -500.000000, -500.000000)


select * from #InvoicesWithBalances

select * from #AvailableCredits

如果我正在执行循环解决方案,那么我将采用最大信用额度,并开始按从大到小的顺序将其应用于发票,直到信用额度余额为零,然后我将继续下一个信用证直到我没有学分,也没有发票。 在下面的示例中,应充分使用前2个信用。第三个信用应部分使用,最后一个信用应保持不变 有什么建议吗?

1 个答案:

答案 0 :(得分:1)

我尝试在此处模拟您的示例:

create table InvoicesWithBalances
(
InvoiceKey int not null,
APBalance int null,
BalanceAfterCreditApplied int null,

);
create table AvailableCredits
(
credit_id int identity(1,1),
StartingBalance int null,
CurrentBalance int null,

);

insert into InvoicesWithBalances values (5452, 13744, 13744);
insert into InvoicesWithBalances values (7056, 13744, 13744);
insert into InvoicesWithBalances values (7438, 500, 500);
insert into AvailableCredits values ( -13744, -13744);
insert into AvailableCredits values ( -13700, -13700);
insert into AvailableCredits values ( -500, -500);
insert into AvailableCredits values ( -500, -500);

create table #invoice (invoice_row_num int, InvoiceKey int, APBalance int, BalanceAfterCreditApplied int);

insert into #invoice 
    select ROW_NUMBER() OVER (ORDER BY APBalance desc) as row_num, InvoiceKey, APBalance, BalanceAfterCreditApplied FROM InvoicesWithBalances;


create table #credits (credit_row_num int, StartingBalance int, CurrentBalance int);

insert into #credits
    select ROW_NUMBER() OVER (ORDER BY StartingBalance asc) as row_num, StartingBalance, CurrentBalance FROM AvailableCredits;

create table #invoice_credit_list (invoice_credit_row_num int, init_invoice int, init_credit int);

if ((select max(invoice_row_num) from #invoice) > (select max(credit_row_num) from #credits))

    insert into #invoice_credit_list
      select i.invoice_row_num , i.APBalance, (-isnull(c.StartingBalance,0)) from 
      #invoice i
      left join 
      #credits c
      on 
      i.invoice_row_num = c.credit_row_num;
else
     insert into #invoice_credit_list
      select c.credit_row_num, isnull(i.APBalance,0), (-c.StartingBalance) from 
      #credits c
      left join 
      #invoice i
      on 
      i.invoice_row_num = c.credit_row_num;




with cte as
(
    select 
    invoice_credit_row_num,
    init_invoice,
    init_credit,
    case when  init_invoice >= init_credit then
         init_invoice - init_credit
         else
         0
         end as 'invoice_remaining',
    case when  init_credit >= init_invoice then
         init_credit - init_invoice
         else
         0
         end as 'credit_remaining'
    from
    #invoice_credit_list i
    where
    i.invoice_credit_row_num = 1

    UNION ALL

    select 
    i.invoice_credit_row_num,
    i.init_invoice + cte.invoice_remaining as 'init_invoice',
    i.init_credit + cte.credit_remaining as 'init credit',
    case when  (i.init_invoice + cte.invoice_remaining) >= (i.init_credit + cte.credit_remaining ) then
         (i.init_invoice + cte.invoice_remaining) - (i.init_credit + cte.credit_remaining )
         else
         0
         end as 'invoice_remaining',
    case when (i.init_credit + cte.credit_remaining) >= (i.init_invoice + cte.invoice_remaining) then
         (i.init_credit + cte.credit_remaining) - (i.init_invoice + cte.invoice_remaining)
         else
         0
         end as 'credit_remaining'
    from
    #invoice_credit_list i
    inner join
    cte
    ON
    i.invoice_credit_row_num - 1 = cte.invoice_credit_row_num
    AND
    i.invoice_credit_row_num > 1


)
select * from cte;

,您还可以在以下位置找到此模拟及其输出:https://rextester.com/SJYGV76640

模拟中的“ cte”表将为您提供所有详细信息。

尽管如此,现在已经在数据库端完成了,我不确定它的性能。因此,请比较并评估其性能。

注意:

  1. ,如果执行速度更快,更好和更好。但是,最多不要在T-SQL中选择循环。

  2. 如果效果不好,请尝试使用C#,VB等任何其他编程语言进行循环。

  3. 如果没有其他选择适合您,请在T-SQL中进行循环。但是,随着数据的增加,我不确定服务器会如何反应:(

希望这对您有所帮助:)