首页 > 解决方案 > 在 SQL 中从每月付款计算利率

问题描述

有没有办法在 SQL (Oracle) 中知道贷款金额、每月付款和期限来计算利率?我可以在知道利率的情况下轻松计算付款,但是相反的方法似乎要困难得多。

每月还款计算(利率 = 0.1 (10%),贷款规模 = 1000,期限 = 24):

   select (0.1/12 * 1000) / (1 - power(1 + 0.1/12, -24)) as mpayment 
   from dual;
   46.1449263375165

问题是如何从每月支付 46.14 美元、贷款规模 1,000 美元、期限 24 个月并计算 10% 作为利率。

例如,在 MS Excel 中,要使用的函数是RATE()

标签: oracleoracle12cfinance

解决方案


正如我在您帖子下方的评论中所说:您正在寻找的东西被称为“内部收益率”。实际上,您正在寻找一种非常特殊的情况 - 定期还款的摊销贷款。Oracle 在附加包中提供了 IRR 功能;如果您只想使用基本 SQL 和 PL/SQL,则必须使用 UDF(用户定义函数)。

这是一种使用牛顿法对其进行编码的方法。我同时演示了几件事。注意数字数据类型(特定于 PL/SQL,不能在普通 SQL 中使用;但是,运行时会将输入从 NUMBER 转换为 PL/SQL 数据类型,并将返回值转换回 NUMBER,透明)。在代码中使用这些数据类型可以使函数更快 - 特别是如果您使用本机编译(正如我在下面的第一行代码中所示)。

到目前为止,一切都应该在旧版本的 PL/SQL 中工作。仅从 12.1 版开始,并且仅当您主要从 SQL 调用该函数时,您才可以使用pragma udf声明 - 这将加速调用该函数的纯 SQL 代码。

该函数返回一个“年化”抵押贷款利率(它计算月利率,然后简单地乘以 12 - 没有复利 - 因为这就是抵押贷款利率的工作方式,至少在美国是这样)。比率以十进制数返回,而不是乘以 100;也就是说,不是百分比。如果函数返回的利率为 0.038,则意味着 3.8%(每年的抵押贷款利率)。在最后的简短演示中,我应该如何将函数调用包装在其他 SQL 代码中以美化答案。

对于最后的例子,我取了200,000的本金,以6.5%的利率计算了30年(360个月)的月供;我每月支付 1,264.14。然后我根据其他值计算利率。

该函数需要本金和每月付款,两者均非空且假定为正数。术语(IN MONTHS)也是需要的,但我编码了一个默认值 360。(也许最好不要为此编码默认值并将其设为必需。)您可以选择输入所需的精度;我默认编码了非常高的精度,因为无论如何计算都非常快。

我没有编写任何类型的错误处理代码;显然,如果您选择将此功能(或任何类似功能)用于培训/学习以外的任何目的,则必须这样做。

alter session set plsql_code_type = native;

create or replace function mortgage_rate(
  p_principal       simple_double
, p_monthly_payment simple_double
, p_term            simple_integer default 360
, p_precision       simple_double  default 0.00000001
)
return number
as 
  pragma udf;     --  Comment out this line if Oracle version is < 12.1
  z     simple_double  := p_monthly_payment/p_principal; 
  u     simple_double  := 1 / (p_term * z);
  v     simple_double  := 0;
  delta simple_double  := 0;
begin
  for i in 1 .. 100 loop
    v     := power(u, p_term);
    delta := ( z * u * ( v - 1) - u + 1 ) / ( z * (p_term + 1) * v - z - 1 );
    u     := u - delta;
    exit when abs(delta) < p_precision;
  end loop;
  return 12 * (1/u - 1);
end;
/


select to_char( 100 * mortgage_rate(200000, 1264.14, 360), 'fm990.000')
       || '%' as interest_rate
from   dual; 


INTEREST_RATE
----------------
6.500%

推荐阅读