sql >> Database >  >> RDS >> Oracle

Leeftijd berekenen vanaf verjaardag met oracle plsql-trigger en de leeftijd in de tabel invoegen

help alsjeblieft... ik heb dit echt nodig...

Nee, dat doe je niet. Ik weet niet zeker of je oplet; en er is geen reden waarom je zou moeten :-) maar:

Sla leeftijd niet op in uw database. Het is absoluut gegarandeerd dat je af en toe ongelijk hebt. De leeftijd verandert elk jaar voor elke persoon, maar voor sommige mensen verandert het elke dag. Dit betekent op zijn beurt dat u een batchtaak nodig hebt om elke dag uit te voeren en de leeftijd bij te werken. Als dit niet lukt, of niet extreem strikt . is en twee keer wordt weggestuurd, zit je in de problemen.

Je moet altijd bereken de leeftijd wanneer je het nodig hebt. Het is een vrij eenvoudige vraag en bespaart je op de langere termijn veel pijn.

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

Ik heb een kleine SQL Fiddle opgezet om te demonstreren

Nu, om uw vraag daadwerkelijk te beantwoorden

deze procedure werkt prima, maar voor slechts één rij,,, maar voor alle rijen is een trigger nodig, maar als ik het vanuit een trigger aanroep, treedt de fout op...

U vermeldt de fout niet, doe dit alstublieft in de toekomst, want het is erg handig, maar ik vermoed dat u

krijgt

ORA-04091:tabel string.string muteert, trigger/functie ziet het mogelijk niet

Dit komt omdat uw procedure de tabel opvraagt ​​die wordt bijgewerkt. Oracle staat dit niet toe om een ​​leesconsistent beeld van de gegevens te behouden. De manier om dit te voorkomen, is door de tabel niet op te vragen, wat u ook niet hoeft te doen. Verander uw procedure in een functie die het juiste resultaat retourneert op basis van een geboortedatum:

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;

Merk nogmaals op dat ik de months_between() . gebruik functioneren omdat niet alle jaren 365 dagen hebben.

In uw trigger wijst u de waarde vervolgens rechtstreeks aan de kolom toe.

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

De :new.<column> syntaxis is een verwijzing naar de <column> dat wordt bijgewerkt. In dit geval :new.age is de werkelijke waarde die in de tabel wordt gezet.

Dit betekent dat uw tabel automatisch wordt bijgewerkt, wat het punt is van een DML-trigger.

Zoals je kunt zien, heeft de functie helemaal geen zin; je trigger kan worden

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; 

Dat gezegd hebbende, als u deze functie elders in de database gaat gebruiken, houd deze dan apart. Het is een goede gewoonte om code die op meerdere plaatsen wordt gebruikt in een functie als deze te bewaren, zodat deze altijd op dezelfde manier wordt gebruikt. Het zorgt er ook voor dat wanneer iemand zijn leeftijd berekent, hij het ook goed doet.

Even terzijde, weet je zeker dat je wilt dat mensen 9.999 jaar oud zijn? Of 0,00000000001998 (bewijs)? Numerieke precisie is gebaseerd op het aantal significante cijfers; dit (volgens Oracle) is niet-nul alleen nummers. U kunt hierdoor gemakkelijk worden betrapt. Het doel van een database is om de mogelijke invoerwaarden te beperken tot alleen geldige waarden. Ik zou serieus overwegen om je leeftijdskolom te declareren als number(3,0) om ervoor te zorgen dat alleen "mogelijke" waarden worden opgenomen.



  1. Converteer 'time' naar 'datetime2' in SQL Server (T-SQL-voorbeelden)

  2. Voormalig Capgemini Executive, Sunitha Ray, sluit zich aan bij ScaleGrid DBaaS om Enterprise Sales uit te breiden

  3. Overlappende zoekopdrachten optimaliseren Deel 1:Introductie en verbeterde T-SQL-oplossing

  4. Selecteer een willekeurige rij uit een PostgreSQL-tabel met gewogen rijkansen