На просторах Интернета не сложно найти 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; |
Если на этапе заполнения базы данных разработчики не предусмотрели механизма предварительной проверки правильности e-mail, то полезной будет следующая функция. Она возвращает 1, если адрес электронной почты корректен, и код ошибки в противном случае:
CREATE OR REPLACE FUNCTION EMAIL_CHECK (email varchar2) --проверяет адрес эл. почты 1 - else - not ok /********************************************/ --КОДЫ ОШИБОК --0 Пустой email --99 Нет символа @ или не заполнено имя пользователя или пароль --100 Введённый email содержит пробелы в имени пользователя. --101 Точка (.), в имени пользователя не может быть первым символом. --102 Минус (-), в имени пользователя не может быть первым символом. --103 Подчёркивание (_), в имени пользователя не может быть первым символом. --104 Введённый email содержит недопустимые символы в имени пользователя --105 Введённый email содержит пробелы в домене. --106 Домен должен содержать хотя бы одну точку (.). --107 Точка (.), в домене не может быть первым или последним символом. --108 Введённый email содержит недопустимые символы в домене --109 Введённый email содержит недопустимые символы в суффиксе домена (то, что написано после последней точки) /********************************************/ RETURN INT IS R INT:= 1; username VARCHAR(200); DOMAIN VARCHAR(200); msg VARCHAR(255); temp_str VARCHAR(200); len INT; BEGIN IF ltrim(rtrim(email)) IS NOT NULL THEN username:=LOWER(substr(email,1,instr(email,'@')-1)); DOMAIN:=LOWER(substr(email,instr(email,'@')+1,LENGTH(email)-instr(email,'@')+1)); -- проверка @ и длины имени пользователя и домена IF LENGTH(username)=0 OR LENGTH(DOMAIN)=0 THEN R := 99; END IF; -- проверка правильности имени пользователя IF instr(username,' ')!=0 THEN R := 100; END IF; IF substr(username,1,1)='.' THEN R := 101; END IF; IF substr(username,1,1)='-' THEN R := 102; END IF; IF substr(username,1,1)='_' THEN R := 103; END IF; temp_str:=REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(username,'a',''),'b',''),'c',''),'d',''),'e',''),'f',''),'g',''),'h',''),'i',''),'j',''),'k',''),'l',''),'m',''),'n',''),'o',''),'p',''),'q',''),'r',''),'s',''),'t',''),'u',''),'v',''),'w',''),'x',''),'y',''),'z',''),'.',''),'_',''),'-',''),'0',''),'1',''),'2',''),'3',''),'4',''),'5',''),'6',''),'7',''),'8',''),'9',''); IF LENGTH(temp_str)<>0 THEN R := 104; END IF; -- проверка правильности домена IF instr(DOMAIN,' ')!=0 THEN R := 105; END IF; IF instr(DOMAIN,'.')=0 THEN R := 106; END IF; IF substr(DOMAIN,1,1)='.' OR substr(DOMAIN,LENGTH(DOMAIN),1)='.' THEN R := 107; END IF; temp_str:=REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(DOMAIN,'a',''),'b',''),'c',''),'d',''),'e',''),'f',''),'g',''),'h',''),'i',''),'j',''),'k',''),'l',''),'m',''),'n',''),'o',''),'p',''),'q',''),'r',''),'s',''),'t',''),'u',''),'v',''),'w',''),'x',''),'y',''),'z',''),'.',''),'-',''),'0',''),'1',''),'2',''),'3',''),'4',''),'5',''),'6',''),'7',''),'8',''),'9',''); IF LENGTH(temp_str)<>0 THEN R := 108; END IF; len:=LENGTH(DOMAIN); while len>0 loop IF substr(DOMAIN,len,1)='.' THEN exit; END IF; len := len - 1; END loop; temp_str:=REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(substr(DOMAIN,len+1,LENGTH(DOMAIN)-len+1),'a',''),'b',''),'c',''),'d',''),'e',''),'f',''),'g',''),'h',''),'i',''),'j',''),'k',''),'l',''),'m',''),'n',''),'o',''),'p',''),'q',''),'r',''),'s',''),'t',''),'u',''),'v',''),'w',''),'x',''),'y',''),'z',''); IF LENGTH(temp_str)<>0 THEN R := 109; END IF; ELSE R := 0; END IF; RETURN(R); END; |
Продолжить чтение »