На просторах Интернета не сложно найти 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; |