sql >> Databáze >  >> RDS >> Oracle

Výpočet věku od narozenin pomocí oracle plsql trigger a vložení věku do tabulky

prosím pomozte...opravdu to potřebuji...

Ne, nechceš. Nejsem si jistý, že budete věnovat pozornost; a není důvod, proč byste měli :-) ale:

Neukládejte věk do databáze. Určitě se občas zmýlíte. Věk se u každého člověka mění každý rok, u některých se však mění každý den. To zase znamená, že potřebujete každý den spouštět dávkovou úlohu a aktualizovat věk. Pokud to selže nebo není extrémně přísné a dostanete se dvakrát, máte potíže.

Měli byste vždy vypočítat věk, kdy to potřebujete. Je to poměrně jednoduchý dotaz a z dlouhodobého hlediska vám ušetří spoustu bolesti.

select floor(months_between(sysdate,<dob>)/12) from dual

Nastavil jsem malou SQL Fiddle, abych ji demonstroval

Nyní, abych skutečně odpověděl na vaši otázku

tento postup funguje dobře, ale pouze pro jeden řádek,,,ale pro všechny řádky potřebují spouštěč, ale pokud jej zavolám ze spouštěče, dojde k chybě...

Nezmiňujete chybu, udělejte to prosím v budoucnu, protože je to velmi užitečné, ale mám podezření, že dostáváte

ORA-04091:tabulka string.string mutuje, spouštěč/funkce to nemusí vidět

Důvodem je, že váš postup dotazuje tabulku, která je aktualizována. Oracle to neumožňuje, aby zachoval konzistentní zobrazení dat pro čtení. Způsob, jak se tomu vyhnout, je nedotazovat se na tabulku, což nemusíte dělat. Změňte svůj postup na funkci, která vrací správný výsledek s datem narození:

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;

Ještě jednou si všimněte, že používám months_between() fungovat, protože ne všechny roky mají 365 dní.

Ve vašem spouštěči pak přiřadíte hodnotu přímo sloupci.

CREATE OR REPLACE TRIGGER agec before INSERT OR UPDATE ON dates
FOR EACH ROW
BEGIN
   :new.age := get_age(:new.dob);
END;

:new.<column> syntaxe je odkaz na <column> který se aktualizuje. V tomto případě :new.age je skutečná hodnota, která bude vložena do tabulky.

To znamená, že vaše tabulka bude automaticky aktualizována, což je bod spouštěče DML.

Jak vidíte, tato funkce nemá vůbec žádný smysl; váš spouštěč se může stát

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; 

Nicméně, pokud budete tuto funkci používat jinde v databázi, ponechte ji oddělenou. Je dobrým zvykem ponechat kód, který se používá na více místech ve funkci, jako je tato, aby byl vždy používán stejným způsobem. Zajišťuje také, že kdykoli někdo spočítá věk, udělá to správně.

Trochu stranou, jste si jistý, že chcete umožnit lidem, aby byli starší 9999 let? Nebo 0,000000000001998 (důkaz)? Numerická přesnost je založena na počtu významných číslice; toto (podle Oracle) je nenulové pouze čísla. Můžete se tím snadno nechat nachytat. Smyslem databáze je omezit možné vstupní hodnoty pouze na ty, které jsou platné. Vážně bych zvážil deklarování sloupce věku jako number(3,0) abyste zajistili, že budou zahrnuty pouze "možné" hodnoty.



  1. Jak funguje funkce SQL Server DIFFERENCE().

  2. Jak změnit SADA ZNAKŮ (a COLLATION) v celé databázi?

  3. Jak se vyhnout použití + v čísle verze s SQLiteAssetHelper

  4. Jak funguje funkce CONCAT() v PostgreSQL