2013-11-27 72 views
3

我一直在寫SQL查詢多年,但我堅持在這一個。計算貸款支付時支付滿意 - 部分支付允許

我有2代表在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 */ 

報告查詢應該簡單地提供PAIDDATE當每個LOANPAYMENTSDUE很滿意。使用報告上面的表中的數據將是如下:

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

哇,這是一個具有挑戰性的真正感謝 –

回答

0

您可以用這兩個查詢,返回所有行與總運行列開始:

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

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

,然後你可以使用LEFT JOIN上due.LoanId = due.LoanId AND total_due < = total_paid,和一羣以獲得其中聯接succeded最小日期:

SELECT 
    ld.LoanId, ld.DueDate, MIN(lp.PaidDate) 
FROM 
    (SELECT 
    LoanId, DueDate, 
    CASE WHEN [email protected]_LoanId1 THEN @Due:[email protected]+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 [email protected]_LoanId2 THEN @Paid:[email protected]+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

+0

fthiella!我喜歡你的解決方案,並且在測試不同的場景後,它效果很好我喜歡看到2個不同的數據集與運行總數。基於total_due和total_paid的LEFT JOIN很有效。 –

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; 
+0

好吧,這是一個有趣的 –

+0

感謝您的幫助天津。 –