Как я сказал в комментарии под вашим постом: то, что вы ищете, называется «внутренней нормой прибыли».На самом деле вы ищете совершенно особый случай - амортизированный кредит с равными выплатами через равные промежутки времени.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 основных значений и рассчитал ежемесячный платеж.свыше 30 лет (360 месяцев) с процентной ставкой 6,5%;Я получил ежемесячный платеж в размере 1264,14.Затем я вычисляю процентную ставку из других значений.
Функция требует основную сумму и ежемесячный платеж, как NOT NULL, так и предполагаемые положительные.Термин (В МЕСЯЦАХ) также необходим, но я кодировал значение по умолчанию 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%