sql >> Database teknologi >  >> RDS >> Oracle

Beregn alder fra fødselsdag med oracle plsql trigger og indsæt alderen i tabellen

venligst hjælp...jeg har virkelig brug for dette...

Nej, det gør du ikke. Jeg er ikke sikker på, at du vil være opmærksom; og det er der ingen grund til at du skal :-) men:

Gem ikke alder i din database. Du er helt garanteret at tage fejl af og til. Alder ændrer sig hvert år for hver person, men det ændrer sig hver dag for nogle mennesker. Dette betyder igen, at du har brug for et batchjob til at køre hver dag og opdatere alder. Hvis dette mislykkes, eller ikke er ekstremt strengt og bliver kørt to gange, er du i problemer.

Du bør altid beregn alderen, når du har brug for det. Det er en ret simpel forespørgsel og sparer dig for mange smerter på længere sigt.

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

Jeg har oprettet en lille SQL Fiddle for at demonstrere

Nu, for faktisk at besvare dit spørgsmål

denne procedure fungerer fint, men for kun én række,,, men for alle rækkerne skal triggeren, men hvis jeg kalder den fra en trigger, opstår fejlen...

Du nævner ikke fejlen. Gør venligst dette fremover, da det er meget nyttigt, men jeg formoder, at du får

ORA-04091:tabel string.string muterer, trigger/funktion ser det muligvis ikke

Dette skyldes, at din procedure forespørger på den tabel, der opdateres. Oracle tillader ikke dette for at opretholde en læsekonsistent visning af dataene. Måden at undgå dette på er ikke at forespørge i tabellen, hvilket du ikke behøver at gøre. Skift din procedure til en funktion, der returnerer det korrekte resultat givet en fødselsdato:

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;

Bemærk igen, at jeg bruger months_between() fungerer, da ikke alle år har 365 dage.

I din trigger tildeler du derefter værdien direkte til kolonnen.

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

:new.<column> syntaks er en reference til <column> der bliver opdateret. I dette tilfælde :new.age er den faktiske værdi, der vil blive sat i tabellen.

Det betyder, at din tabel automatisk vil blive opdateret, hvilket er punktet for en DML-trigger.

Som du kan se, er der ingen mening med funktionen overhovedet; din trigger kan blive

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; 

Men når det er sagt, hvis du skal bruge denne funktion andre steder i databasen, så hold den adskilt. Det er god praksis at opbevare kode, der bruges flere steder i en funktion som denne, så den altid bruges på samme måde. Det sikrer også, at når nogen beregner alder, vil de gøre det ordentligt.

Som en lille side er du sikker på, at du vil tillade folk at være 9.999 år gamle? Eller 0,000000000001998 (bevis)? Numerisk præcision er baseret på antallet af signifikante cifre; dette (ifølge Oracle) er ikke-nul kun numre. Det kan du nemt blive fanget af. Pointen med en database er at begrænse de mulige inputværdier til kun dem, der er gyldige. Jeg vil seriøst overveje at erklære din alderskolonne som number(3,0) for at sikre, at kun "mulige" værdier er inkluderet.



  1. Sådan gør du dine adgangsdatabaser ultrahurtige!

  2. Postgres 9.1 vs Mysql 5.6 InnoDB?

  3. Forespørger på en linket sql-server

  4. migrere data fra MS SQL til PostgreSQL?