Oracle SQL - 计算未来贷款

时间:2014-08-20 01:45:42

标签: sql oracle plsql

我正在尝试根据以下公式计算出一个SQL查询来计算未来贷款余额

FV (未来余额)= 简历(当前余额) - P (修复还款)+ (利息资本化)

其中**我 =( CV * APR (年度百分比率) / 365 * D (期间之间的天数))

以下是原始数据示例:

Account ID    Principal        P (Payment)    APR 
123           $10,000.00      $200.00        0.2

以下是示例输出:

Term    Account ID  CV (Current Balance)    P (Payment) APR  D (Days)   I (Interest Cap)    FV (Future Balance)
1       123         $10,000.00           $200.00      0.2  31         169.86              $9,969.86 
2       123         $9,969.86                $200.00      0.2  30         163.89              $9,933.75 
3       123         $9,933.75                $200.00      0.2  31         168.74              $9,902.49 
4       123         $9,902.49                $200.00      0.2  30         162.78              $9,865.27 
.....
N       123         <Term N-1 FV>           $200.00     0.2  30         Derived Interest    Derived FV

CV的值始终是前一个词的FV(FV是根据公式计算的)

我当前的约束是我没有足够的权限在我的SQL环境中创建过程或函数

Excel 上似乎是一个简单的练习,但是如果不使用过程/函数,我无法弄清楚如何在SQL中执行....

2 个答案:

答案 0 :(得分:3)

如果您使用的是Oracle 11gR2,则可以使用递归CTE。

SQL Fiddle

create table mytable(
    account_id  number,
    principal   number,
    payment     number,
    apr         number
);

insert into mytable values(123, 10000, 200, 0.2);
insert into mytable values(124, 7000,  180, 0.22);

with x(term, account_id, current_balance, payment, apr, days, interest, future_balance) as (
    select  1,
            account_id,
            principal,
            payment,
            apr,
            extract(day from last_day(sysdate)),
            principal * apr * extract(day from last_day(sysdate)) / 365,
            (principal * apr * extract(day from last_day(sysdate)) / 365) + principal - payment
    from mytable
    union all
    select  term + 1,
            account_id,
            future_balance,
            payment,
            apr,
            extract(day from last_day(add_months(sysdate, term))),
            future_balance * apr * extract(day from last_day(add_months(sysdate, term))) / 365,
            (future_balance * apr * extract(day from last_day(add_months(sysdate, term))) / 365) + future_balance - payment
    from x
    where term <= 5
)
select * from x
order by 2,1

<强> Results

| TERM | ACCOUNT_ID |   CURRENT_BALANCE | PAYMENT |  APR | DAYS |         INTEREST |    FUTURE_BALANCE |
|------|------------|-------------------|---------|------|------|------------------|-------------------|
|    1 |        123 |             10000 |     200 |  0.2 |   31 |  169.86301369863 |  9969.86301369863 |
|    2 |        123 |  9969.86301369863 |     200 |  0.2 |   30 | 163.888159129293 | 9933.751172827922 |
|    3 |        123 | 9933.751172827922 |     200 |  0.2 |   31 | 168.737691154885 | 9902.488863982808 |
|    4 |        123 | 9902.488863982808 |     200 |  0.2 |   30 | 162.780638859991 | 9865.269502842799 |
|    5 |        123 | 9865.269502842799 |     200 |  0.2 |   31 | 167.574440870206 | 9832.843943713006 |
|    6 |        123 | 9832.843943713006 |     200 |  0.2 |   31 | 167.023650550741 | 9799.867594263747 |
|    1 |        124 |              7000 |     180 | 0.22 |   31 | 130.794520547945 | 6950.794520547946 |
|    2 |        124 | 6950.794520547946 |     180 | 0.22 |   30 | 125.685599549634 | 6896.480120097579 |
|    3 |        124 | 6896.480120097579 |     180 | 0.22 |   31 | 128.860258682371 | 6845.340378779951 |
|    4 |        124 | 6845.340378779951 |     180 | 0.22 |   30 | 123.778757534103 | 6789.119136314053 |
|    5 |        124 | 6789.119136314053 |     180 | 0.22 |   31 | 126.854226053868 | 6735.973362367922 |
|    6 |        124 | 6735.973362367922 |     180 | 0.22 |   31 | 125.861200907806 | 6681.834563275728 |

UNION查询的第一部分选择表中的数据,将术语编号指定为1,计算当月的天数,计算利息和未来余额。

查询的第二部分基于前一步骤的计算结果迭代地计算同一组数据。只要满足where clause,您就可以继续这样做,您可以使用该术语来限制术语数量。

答案 1 :(得分:2)

另一种方法是使用MODEL子句。

SQL Fiddle

WITH x (term, account_id, current_balance, payment, apr, days, interest, future_balance)
     AS (SELECT 1,
                account_id,
                principal,
                payment,
                apr,
                EXTRACT (DAY FROM LAST_DAY (SYSDATE)),
                principal * apr * EXTRACT (DAY FROM LAST_DAY (SYSDATE)) / 365,
                  (  principal * apr * EXTRACT (DAY FROM LAST_DAY (SYSDATE)) / 365)
                + principal
                - payment
           FROM mytable)
SELECT *
  FROM x
MODEL
   PARTITION BY (account_id)
   DIMENSION BY (term)
   MEASURES (current_balance, payment, apr, days, interest, future_balance)
   RULES
      ITERATE (4)                                                                           --number of terms to be generated
      (current_balance [FOR term FROM 2 TO 5 INCREMENT 1] = future_balance[CV (term) - 1],  --range of terms to generated
      payment [term] = payment[1],
      apr [term] = apr[1],
      days [term] = EXTRACT (DAY FROM LAST_DAY (ADD_MONTHS (SYSDATE, CV (term) - 1))),
      interest [term] =
              current_balance[CV (term)] * apr[CV (term)] * days[CV (term)] / 365,
      future_balance [term] = interest[CV (term)] - payment[CV (term)] + current_balance[CV (term)])

<强> Results

| ACCOUNT_ID | TERM |   CURRENT_BALANCE | PAYMENT |  APR | DAYS |         INTEREST |    FUTURE_BALANCE |
|------------|------|-------------------|---------|------|------|------------------|-------------------|
|        123 |    1 |             10000 |     200 |  0.2 |   31 |  169.86301369863 |  9969.86301369863 |
|        123 |    2 |  9969.86301369863 |     200 |  0.2 |   30 | 163.888159129293 | 9933.751172827922 |
|        123 |    3 | 9933.751172827922 |     200 |  0.2 |   31 | 168.737691154885 | 9902.488863982808 |
|        123 |    4 | 9902.488863982808 |     200 |  0.2 |   30 | 162.780638859991 | 9865.269502842799 |
|        123 |    5 | 9865.269502842799 |     200 |  0.2 |   31 | 167.574440870206 | 9832.843943713006 |
|        124 |    1 |              7000 |     180 | 0.22 |   31 | 130.794520547945 | 6950.794520547946 |
|        124 |    2 | 6950.794520547946 |     180 | 0.22 |   30 | 125.685599549634 | 6896.480120097579 |
|        124 |    3 | 6896.480120097579 |     180 | 0.22 |   31 | 128.860258682371 | 6845.340378779951 |
|        124 |    4 | 6845.340378779951 |     180 | 0.22 |   30 | 123.778757534103 | 6789.119136314053 |
|        124 |    5 | 6789.119136314053 |     180 | 0.22 |   31 | 126.854226053868 | 6735.973362367922 |

一开始可能看起来令人生畏,但我使用了与递归cte完全相同的计算。如果您浏览White paper,您将更好地理解每个条款。

此外,这也适用于早期版本的Oracle。