【问题标题】:Regenerate the loan payment table by redistribution of paid amounts通过重新分配已支付金额重新生成贷款支付表
【发布时间】:2016-06-29 10:36:06
【问题描述】:

我的桌子上有分期付款记录,如下图。最初,本金分配为 2500,但经过一段时间后,金额增加了 1000 并变为 3500。现在应重新分配付款表。最初每期支付2500,我需要分配该金额,以便新的分期金额总和为3500。

--Initial Records
CREATE TABLE #LOAN_REPAYMENT
( 
TRAN_DATE DATETIME,
INSTALLMENT_NO INT,
PAID_AMOUNT DECIMAL(18,2)
)

INSERT INTO #LOAN_REPAYMENT VALUES ('1/15/2016', 11, 2000)
GO
INSERT INTO #LOAN_REPAYMENT VALUES ('2/15/2016', 11, 500)
GO  
INSERT INTO #LOAN_REPAYMENT VALUES ('3/15/2016', 12, 700)
GO
INSERT INTO #LOAN_REPAYMENT VALUES ('3/28/2016', 12, 1800)
GO
INSERT INTO #LOAN_REPAYMENT VALUES ('3/28/2016', 13, 2500)
GO
INSERT INTO #LOAN_REPAYMENT VALUES ('4/15/2016', 14, 2500)
GO
INSERT INTO #LOAN_REPAYMENT VALUES ('4/15/2016', 15, 1500)
GO

结果应该是这样的

CREATE TABLE #LOAN_REPAYMENT_NEW
( 
TRAN_DATE DATETIME,
INSTALLMENT_NO INT,
PAID_AMOUNT DECIMAL(18,2)
)

INSERT INTO #LOAN_REPAYMENT_NEW VALUES ('1/15/2016', 11, 2000)
GO
INSERT INTO #LOAN_REPAYMENT_NEW VALUES ('2/15/2016', 11, 500)
GO  
INSERT INTO #LOAN_REPAYMENT_NEW VALUES ('3/15/2016', 11, 700)
GO
INSERT INTO #LOAN_REPAYMENT_NEW VALUES ('3/28/2016', 11, 300)
GO
INSERT INTO #LOAN_REPAYMENT_NEW VALUES ('3/28/2016', 12, 1500)
GO
INSERT INTO #LOAN_REPAYMENT_NEW VALUES ('3/28/2016', 12, 2000)
GO
INSERT INTO #LOAN_REPAYMENT_NEW VALUES ('3/28/2016', 13, 500)
GO
INSERT INTO #LOAN_REPAYMENT_NEW VALUES ('4/15/2016', 13, 2500)
GO
INSERT INTO #LOAN_REPAYMENT_NEW VALUES ('4/15/2016', 13, 500)
GO
INSERT INTO #LOAN_REPAYMENT_NEW VALUES ('4/15/2016', 14, 1000)
GO

【问题讨论】:

  • 你想为 sql-generator 使用什么语言?是 sql-query 还是 c# 还是 java?
  • 我想要这个在 TSQL 上

标签: sql sql-server tsql common-table-expression


【解决方案1】:

我假设最后一条记录的 installment_no 值应为 14(结果屏幕截图显示为 13,结果代码显示为 14)。我在代码 cmets 中包含了我对答案的解释。

if object_id('tempdb..#loan_repayment') is not null
    drop table #loan_repayment

if object_id('tempdb..#loan_repayment_final') is not null
    drop table #loan_repayment_final

CREATE TABLE #LOAN_REPAYMENT
( 
TRAN_DATE DATETIME,
INSTALLMENT_NO INT,
PAID_AMOUNT DECIMAL(18,2)
)

--creating the temp table for final results
CREATE TABLE #LOAN_REPAYMENT_FINAL
( 
TRAN_DATE DATETIME,
INSTALLMENT_NO INT,
PAID_AMOUNT DECIMAL(18,2),
TRAN_RANK INT,
ITER_VAL INT
)

--inserting inital sample data
INSERT INTO #LOAN_REPAYMENT VALUES ('1/15/2016', 11, 2000)
GO
INSERT INTO #LOAN_REPAYMENT VALUES ('2/15/2016', 11, 500)
GO  
INSERT INTO #LOAN_REPAYMENT VALUES ('3/15/2016', 12, 700)
GO
INSERT INTO #LOAN_REPAYMENT VALUES ('3/28/2016', 12, 1800)
GO
INSERT INTO #LOAN_REPAYMENT VALUES ('3/28/2016', 13, 2500)
GO
INSERT INTO #LOAN_REPAYMENT VALUES ('4/15/2016', 14, 2500)
GO
INSERT INTO #LOAN_REPAYMENT VALUES ('4/15/2016', 15, 1500)
GO

declare @install_no int = (select min(installment_no) from #loan_repayment) --starting installment_no
declare @install_amt decimal(18,2) = 3500.00 --new installment amount
declare @rec_rank int --used in while loop
declare @i int = 0 --used to track iteration of while loop

if object_id('tempdb..#loan_repayment_rank') is not null
    drop table #loan_repayment_rank

--adding additional derived columns to the initial sample data
select lr.tran_date
, lr.installment_no
, lr.paid_amount
, sum(lr.paid_amount) over (order by lr.tran_date asc, lr.installment_no asc) as unassigned_amt
, row_number() over (order by lr.tran_date asc, lr.installment_no asc) as tran_rank
into #loan_repayment_rank
from #loan_repayment as lr

while exists (select *
              from #loan_repayment_rank as lr
              where 1=1
              and lr.unassigned_amt > 0)
begin

    --finding the highest record rank that should be included in
    --the current installment calculation
    set @rec_rank = coalesce((select min(lrr.tran_rank)
                                from #loan_repayment_rank as lrr
                                where 1=1
                                and unassigned_amt >= @install_amt)
                            , (select min(lrr.tran_rank)
                                from #loan_repayment_rank as lrr
                                where 1=1
                                and unassigned_amt > 0))

    --adding the necessary records to the fianl output
    insert into #loan_repayment_final
    select lrr.tran_date
    , @install_no + @i as installment_no
    , case when lrr.tran_rank < @rec_rank then lrr.paid_amount
           when lrr.tran_rank = @rec_rank and lrr.paid_amount = lrr.unassigned_amt then lrr.paid_amount
           else @install_amt - (select a.unassigned_amt from #loan_repayment_rank as a where tran_rank = @rec_rank - 1)
      end as paid_amount
    , lrr.tran_rank
    , @i as iter_val
    from #loan_repayment_rank as lrr
    where 1=1
    and lrr.tran_rank <= @rec_rank
    and lrr.unassigned_amt > 0

    --decrementing the paid amounts on the source temp table
    --on the records effected by the current installment calculation
    update lr
    set lr.paid_amount = lr.paid_amount - lf.paid_amount
    from #loan_repayment_final as lf
    right join #loan_repayment_rank as lr on lf.tran_rank = lr.tran_rank
    where 1=1
    and lf.iter_val = @i

    --updating the unassigned amount on all records
    update lr
    set lr.unassigned_amt = case when lr.unassigned_amt <= @install_amt then 0.00
                                 else lr.unassigned_amt - @install_amt
                            end
    from #loan_repayment_rank as lr

    --incrementing the iteration
    set @i += 1

end

--final output
select lf.tran_date
, lf.installment_no
, lf.paid_amount
from #loan_repayment_final as lf

【讨论】:

  • 没错!结果如预期。我想知道它是否可以在不使用 while 循环或游标(如使用 CTE 或其他东西)的情况下解决。
  • @barcanoj 不会撒谎,我考虑过使用递归 CTE,但这是我能够想出的解决方案。可能会看看我是否可以使递归 CTE 工作,但没有承诺。
猜你喜欢
  • 2015-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-28
  • 1970-01-01
  • 2016-10-22
  • 1970-01-01
相关资源
最近更新 更多