计算贷款支付&付款满意时 - 允许部分付款

时间:2013-11-27 20:19:40

标签: mysql sql

我多年来一直在编写SQL查询,但我仍然坚持这一点。

我在MySQL中有两个表:

  • LOANPAYMENTSDUE包括LoanPaymentsDueIdLoanIdAmtDueDueDate
  • LOANPAYMENTS包括LoanPaymentsIdLoanIdAmtPaidPaidDate

表格之间的关系是LoanId,而不是到期的具体付款。在一个完美的世界中DueDate = PaidDateAmtDue = AmtPaid。但是,对我来说这复杂的是LoanPaymentsDueIdLoanPaymentsId之间的关系。该关系仅存在于LoanId,允许在单个LOANPAYMENTSDUE付款上进行部分付款。

我研究过网络试图找到正确的查询创建一个显示每个LOANPAYMENTSDUE满足日期的报告。这需要计算LOANPAYMENTSDUE.DueDate的余额,因为可以有付款错过,新付款应满足最早的LOANPAYMENTSDUE付款余额。

以下是示例数据和表脚本:

CREATE TABLE LOANPAYMENTSDUE (
LoanPaymentsDueId BIGINT(20) NOT NULL AUTO_INCREMENT
, LoanId BIGINT(20)
, AmtDue double NOT NULL
, DueDate date NOT NULL
, PRIMARY KEY (LoanPaymentsDueId)
);

INSERT INTO LOANPAYMENTSDUE (LoanId, AmtDue, DueDate) VALUES (1, 100, '2013-07-15');
INSERT INTO LOANPAYMENTSDUE (LoanId, AmtDue, DueDate) VALUES (1, 100, '2013-08-15');
INSERT INTO LOANPAYMENTSDUE (LoanId, AmtDue, DueDate) VALUES (1, 100, '2013-09-15');
INSERT INTO LOANPAYMENTSDUE (LoanId, AmtDue, DueDate) VALUES (1, 100, '2013-10-15');
INSERT INTO LOANPAYMENTSDUE (LoanId, AmtDue, DueDate) VALUES (1, 100, '2013-11-15');

CREATE TABLE LOANPAYMENTS (
LoanPaymentsId BIGINT(20) NOT NULL AUTO_INCREMENT
, LoanId BIGINT(20)
, AmtPaid double NOT NULL
, PaidDate date NOT NULL
, PRIMARY KEY (LoanPaymentsId)
);

INSERT INTO LOANPAYMENTS (LoanId, AmtPaid, PaidDate) VALUES (1, 100, '2013-07-15'); /* Full pmt on due date */
INSERT INTO LOANPAYMENTS (LoanId, AmtPaid, PaidDate) VALUES (1, 100, '2013-08-10'); /* Full pmt a few days early */
INSERT INTO LOANPAYMENTS (LoanId, AmtPaid, PaidDate) VALUES (1, 100, '2013-09-22'); /* Full pmt a week late */
INSERT INTO LOANPAYMENTS (LoanId, AmtPaid, PaidDate) VALUES (1, 50, '2013-10-18'); /* Partial pmt a few days late */
INSERT INTO LOANPAYMENTS (LoanId, AmtPaid, PaidDate) VALUES (1, 50, '2013-11-07');/* Partial pmt 3 weeks late and satisfies the 10/15/2013 balance on this date */
INSERT INTO LOANPAYMENTS (LoanId, AmtPaid, PaidDate) VALUES (1, 100, '2013-11-22');/* Full pmt a week late and satisfies the 11/15/2013 pmt due */

报告查询应该只在满足每个LOANPAYMENTSDUE时提供PAIDDATE。使用报告上方的表格数据如下:

LOANID     LOANPAYMENTSDUEID     AMTDUE     DUEDATE          PAIDDATE
1          1                     100        2013-07-15       2013-07-15    
1          2                     100        2013-08-15       2013-08-10
1          3                     100        2013-09-15       2013-09-22
1          4                     100        2013-10-15       2013-11-07
1          5                     100        2013-11-15       2013-11-22  

2 个答案:

答案 0 :(得分:0)

您可以从这两个查询开始,这两个查询返回具有正在运行的总列的所有行:

SELECT
  LoanId, DueDate,
  CASE WHEN LoanId=@last_LoanId THEN @Due:=@Due+AmtDue
                                ELSE @Due:=AmtDue END total_due,
  @last_LoanId:=LoanId
FROM
  LOANPAYMENTSDUE, (SELECT @last_LoanId:=NULL, @Due:=NULL) t;

SELECT
  LoanId, PaidDate,
  CASE WHEN LoanId=@last_LoanId THEN @Paid:=@Paid+AmtPaid
                                ELSE @Paid:=AmtPaid END total_paid,
  @last_LoanId:=LoanId
FROM
  LOANPAYMENTS, (SELECT @last_LoanId:=NULL, @Paid:=NULL) t;

然后你可以在due.LoanId = due.LoanId和total_due< = total_paid上使用LEFT JOIN,并使用GROUP BY获得连接成功的最小日期:

SELECT
  ld.LoanId, ld.DueDate, MIN(lp.PaidDate)
FROM
  (SELECT
     LoanId, DueDate,
     CASE WHEN LoanId=@last_LoanId1 THEN @Due:=@Due+AmtDue ELSE @Due:=AmtDue END total_due,
     @last_LoanId1:=LoanId
   FROM
     LOANPAYMENTSDUE, (SELECT @last_LoanId1:=NULL, @Due:=NULL) t1) ld
  LEFT JOIN
  (SELECT
     LoanId, PaidDate,
     CASE WHEN LoanId=@last_LoanId2 THEN @Paid:=@Paid+AmtPaid ELSE @Paid:=AmtPaid END total_paid,
     @last_LoanId2:=LoanId
   FROM
     LOANPAYMENTS, (SELECT @last_LoanId2:=NULL, @Paid:=NULL) t2) lp
  ON
    ld.LoanId=lp.LoanId AND ld.total_due<=lp.total_paid
GROUP BY
  ld.LoanId, ld.DueDate

请参阅小提琴here

答案 1 :(得分:0)

假设当支付金额时,它的支付部分或剩余金额全部支付,您可以根据总金额和支付的总金额进行检查。这是sqlFiddle example of your data and query

SELECT T1.LoanId,
       T1.LoanPaymentsDueId,
       T1.AmtDue,
       T1.DueDate,
       T2.PaidDate
FROM
   (SELECT
     LD.LoanPaymentsDueId,
     LD.LoanId,
     LD.DueDate,
     LD.AmtDue,
     (SELECT Sum(AmtDue)
        FROM LOANPAYMENTSDUE LD1
       WHERE LD1.DueDate <= LD.DueDate
         AND LD1.LoanId = LD.LoanId
     )as AmtDueTotal
    FROM
    LOANPAYMENTSDUE LD
   )T1,
   (SELECT
     L.LoanPaymentsId,
     L.LoanId,
     L.PaidDate,
     (SELECT Sum(AmtPaid)
        FROM LOANPAYMENTS L1
       WHERE L1.PaidDate <= L.PaidDate
         AND L1.LoanId = L.LoanId
      )as AmtPaidTotal
   FROM LOANPAYMENTS L
   )T2
WHERE
    T1.LoanId = T2.LoanId
AND T1.LoanId = 1
AND T1.AmtDueTotal = T2.AmtPaidTotal;