【问题标题】:Calculate loan payments & when the payment was satisfed - partial payments allowed计算贷款支付以及何时支付 - 允许部分支付
【发布时间】:2013-11-27 20:19:40
【问题描述】:

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

我在 MySQL 中有 2 个表:

  • LOANPAYMENTSDUE 包括LoanPaymentsDueIdLoanIdAmtDueDueDate
  • 贷款支付包括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  

【问题讨论】:

  • 哇这个真的很有挑战性

标签: mysql sql


【解决方案1】:

您可以从这两个查询开始,它们返回所有行,其中包含运行总计列:

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

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

【讨论】:

  • 感谢 fthiella!我喜欢您的解决方案,并且在测试了不同的场景后效果很好。我喜欢看到 2 个不同的数据集和运行总数。基于 total_due 和 total_paid 的 LEFT JOIN 效果很好。
【解决方案2】:

假设在支付金额时,它是部分支付或全部支付剩余金额,您根据应付总额和已支付总额通过匹配它们来检查。这是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;

【讨论】:

  • 嗯,这有点有趣
  • 感谢您的帮助 Tin Tran。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-06-18
  • 1970-01-01
  • 2010-12-04
  • 1970-01-01
  • 2011-07-19
  • 2014-07-31
  • 2013-05-07
相关资源
最近更新 更多