моля помогнете... наистина имам нужда от това...
Не, не го правиш. Не съм сигурен, че ще обърнете внимание; и няма причина защо трябва :-) но:
Не съхранявайте възрастта във вашата база данни. Гарантирано е, че понякога грешите. Възрастта се променя всяка година за всеки човек, но се променя всеки ден за някои хора. Това от своя страна означава, че имате нужда от пакетно задание, което да изпълнявате всеки ден и да актуализирате възрастта. Ако това не успее или не е изключително стриктно и се стартира два пъти, вие сте в беда.
Трябва винаги изчислете възрастта, когато имате нужда от нея. Това е доста проста заявка и ви спестява много болка в дългосрочен план.
select floor(months_between(sysdate,<dob>)/12) from dual
Настроих малко SQL Fiddle, за да демонстрирам
Сега, за да отговоря всъщност на въпроса ви
тази процедура работи добре, но само за един ред,,,но за всички редове има нужда от тригер, но ако го извикам от тригер, тогава възниква грешката...
Не споменавате грешката, моля, направете това в бъдеще, тъй като е много полезно, но подозирам, че получавате
ORA-04091:таблица string.string се мутира, тригера/функцията може да не го види
Това е така, защото вашата процедура отправя заявка към таблицата, която се актуализира. Oracle не позволява това, за да поддържа последователен изглед на данните за четене. Начинът да избегнете това е да не правите заявки към таблицата, което не е необходимо да правите. Променете процедурата си на функция, която връща правилния резултат при дата на раждане:
function get_age (pDOB date) return number is
/* Return the the number of full years between
the date given and sysdate.
*/
begin
return floor(months_between(sysdate,pDOB)/12);
end;
Забележете още веднъж, че използвам months_between()
функция, тъй като не всички години имат 365 дни.
След това във вашия тригер присвоявате стойността директно на колоната.
CREATE OR REPLACE TRIGGER agec before INSERT OR UPDATE ON dates
FOR EACH ROW
BEGIN
:new.age := get_age(:new.dob);
END;
:new.<column>
синтаксисът е препратка към <column>
който се актуализира. В този случай :new.age
е действителната стойност, която ще бъде поставена в таблицата.
Това означава, че вашата таблица ще се актуализира автоматично, което е точката на задействане на DML.
Както можете да видите, функцията изобщо няма смисъл; вашият спусък може да стане
CREATE OR REPLACE TRIGGER agec before INSERT OR UPDATE ON dates
FOR EACH ROW
BEGIN
:new.age := floor(months_between(sysdate,:new,DOB)/12);
END;
Въпреки това, след като казахте това, ако ще използвате тази функция другаде в базата данни, запазете я отделно. Добра практика е да запазите код, който се използва на множество места във функция като тази, така че винаги да се използва по един и същи начин. Той също така гарантира, че когато някой изчислява възрастта, той ще го направи правилно.
Като малко настрана, сигурни ли сте, че искате да позволите на хората да са на 9 999 години? Или 0,000000000001998 (доказателство)? Числовата точност се основава на броя на значимите цифри; това (според Oracle) е не-нула само числа. Можете лесно да бъдете хванати от това. Целта на базата данни е да ограничи възможните входни стойности само до тези, които са валидни. Сериозно бих обмислил да декларирам колоната ви за възраст като number(3,0)
за да се гарантира, че са включени само „възможните“ стойности.