На просторах Интернета не сложно найти SQL функцию, которая считала бы аннуитетный платёж по данным о величине кредита, процентной ставке и сроку кредита. Но вот готовой функции для другой задачи, а именно поиска процентной ставки по данным об аннуитете, сроке и величине кредита, мне найти не удалось. Решение данной задачи не тривиальное и требует применения численных методов. В Excel есть очень удобная для этого функция СТАВКА(), на аналог которой на языке PHP я наткнулся на StackOverflow. Мне оставалось только переписать код для SQL. Результат можно увидеть ниже.
nper — количество платёжных периодов; pmt — аннуитетный платёж; pv — величина кредита. Для поиска решения используется метод хорд.
create or replace FUNCTION RATE (nper number, pmt number, pv number) RETURN number
as v_result number;
fv number:= 0.0;
s_type int:= 0;
guess number := 0.1;
FINANCIAL_MAX_ITERATIONS int := 5000; --количество итераций
FINANCIAL_PRECISION number:= 1.0e-08; --точность
y number;
y0 number;
y1 number;
f number;
i number;
x0 number;
x1 number;
BEGIN
v_result := guess;
if (abs(v_result) < FINANCIAL_PRECISION) then
y := pv * (1 + nper * v_result) + pmt * (1 + v_result * s_type) * nper + fv;
else
f := exp(nper * ln(1 + v_result));
y := pv * f + pmt * (1 / v_result + s_type) * (f - 1) + fv;
end if;
y0 := pv + pmt * nper + fv;
y1 := pv * f + pmt * (1 / v_result + s_type) * (f - 1) + fv;
-- поиск корня методом хорд
i := 0;
x0 := 0;
x1 := v_result;
while ((abs(y0 - y1) > FINANCIAL_PRECISION) and (i < FINANCIAL_MAX_ITERATIONS)) loop
v_result := (y1 * x0 - y0 * x1) / (y1 - y0);
x0 := x1;
x1 := v_result;
if ((nper * abs(pmt)) > (pv - fv)) then
x1 := abs(x1);
end if;
if (abs(v_result) < FINANCIAL_PRECISION) then
y := pv * (1 + nper * v_result) + pmt * (1 + v_result * s_type) * nper + fv;
else
f := exp(nper * ln(1 + v_result));
y := pv * f + pmt * (1 / v_result + s_type) * (f - 1) + fv;
end if;
y0 := y1;
y1 := y;
i:=i+1;
end loop;
return v_result;
END;