通过重新分配付款金额重新生成贷款支付表

时间:2016-06-29 10:36:06

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

我的表上有分期付款记录,如下所示。最初,本金额被指定为2500,但在一定时期后,金额增加了1000并达到3500.现在应该重新分配付款表。最初为每期分期付款2500,我需要分配该金额,以便新的分期金额为3500.

Initial records

--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

结果应该是 The result table

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

1 个答案:

答案 0 :(得分:1)

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

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