proszę o pomoc... naprawdę tego potrzebuję...
Nie, nie masz. Nie jestem pewien, czy zwrócisz uwagę; i nie ma powodu, dla którego miałbyś :-) ale:
Nie przechowuj wieku w swojej bazie danych. Masz absolutną gwarancję, że od czasu do czasu się pomylisz. Wiek zmienia się co roku dla każdej osoby, jednak dla niektórych zmienia się każdego dnia. To z kolei oznacza, że potrzebujesz zadania wsadowego do codziennego uruchamiania i aktualizowania wieku. Jeśli to się nie powiedzie lub nie jest bardzo surowe i zostanie uruchomiony dwa razy, masz kłopoty.
Powinieneś zawsze obliczyć wiek, kiedy tego potrzebujesz. To dość proste zapytanie i na dłuższą metę oszczędza wiele bólu.
select floor(months_between(sysdate,<dob>)/12) from dual
Przygotowałem małe skrzypce SQL, aby zademonstrować
Teraz, aby odpowiedzieć na twoje pytanie
ta procedura działa dobrze, ale tylko dla jednego wiersza, ale dla wszystkich rowsi potrzebuję wyzwalacza, ale jeśli wywołam go z wyzwalacza, wystąpi błąd...
Nie wspominasz o błędzie, zrób to w przyszłości, ponieważ jest to bardzo pomocne, ale podejrzewam, że otrzymujesz
ORA-04091:tabela string.string mutuje, wyzwalacz/funkcja może go nie widzieć
Dzieje się tak, ponieważ twoja procedura wysyła zapytanie do aktualizowanej tabeli. Oracle nie zezwala na to, aby zachować spójność odczytu danych. Sposobem na uniknięcie tego jest unikanie zapytań do tabeli, czego nie musisz robić. Zmień procedurę na funkcję, która zwraca poprawny wynik podaną datą urodzenia:
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;
Zauważ jeszcze raz, że używam months_between()
działają, ponieważ nie wszystkie lata mają 365 dni.
W wyzwalaczu następnie przypisz wartość bezpośrednio do kolumny.
CREATE OR REPLACE TRIGGER agec before INSERT OR UPDATE ON dates
FOR EACH ROW
BEGIN
:new.age := get_age(:new.dob);
END;
:nowy.
:new.age
to rzeczywista wartość, która zostanie umieszczona w tabeli.
Oznacza to, że Twoja tabela zostanie automatycznie zaktualizowana, co jest punktem wyzwalacza DML.
Jak widać, ta funkcja w ogóle nie ma sensu; Twój wyzwalacz może stać się
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;
Jednak powiedziawszy to, jeśli zamierzasz używać tej funkcji w innym miejscu bazy danych, zachowaj ją oddzielnie. Dobrą praktyką jest przechowywanie kodu, który jest używany w wielu miejscach w takiej funkcji, aby zawsze był używany w ten sam sposób. Zapewnia również, że za każdym razem, gdy ktoś obliczy wiek, zrobi to poprawnie.
Na marginesie, czy na pewno chcesz, aby ludzie mieli 9999 lat? Lub 0.000000000001998 (dowód)? Dokładność liczbowa jest oparta na liczbie znaczących cyfry; to (według Oracle) jest niezerowe tylko liczby. Możesz łatwo zostać przez to złapany. Celem bazy danych jest ograniczenie możliwych wartości wejściowych tylko do tych, które są prawidłowe. Poważnie rozważyłbym zadeklarowanie kolumny wieku jako number(3,0)
aby upewnić się, że uwzględniane są tylko „możliwe” wartości.