sql >> Base de Datos >  >> RDS >> Oracle

Cálculo de la edad desde el cumpleaños con Oracle plsql trigger e inserte la edad en la tabla

por favor ayuda... realmente necesito esto...

No, no lo haces. No estoy seguro de que prestes atención; y no hay ninguna razón por la que deberías hacerlo :-) pero:

No almacene la edad en su base de datos. Está absolutamente garantizado que se equivocará de vez en cuando. La edad cambia cada año para cada persona, sin embargo, cambia todos los días para algunas personas. Esto a su vez significa que necesita un trabajo por lotes para ejecutar todos los días y actualizar la edad. Si esto falla, o no es extremadamente estricto y se ejecuta dos veces, estás en problemas.

Deberías siempre calcula la edad cuando lo necesites. Es una consulta bastante simple y le ahorra muchos dolores de cabeza a largo plazo.

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

Configuré un pequeño SQL Fiddle para demostrar

Ahora, para responder realmente a tu pregunta

este procedimiento funciona bien, pero solo para una fila, pero para todas las filas, necesito un disparador, pero si lo llamo desde un disparador, entonces ocurre el error...

No menciona el error, hágalo en el futuro, ya que es muy útil, pero sospecho que está recibiendo

ORA-04091:cadena de tabla.cadena está mutando, es posible que el activador o la función no lo vean

Esto se debe a que su procedimiento está consultando la tabla que se está actualizando. Oracle no permite esto para mantener una vista coherente de lectura de los datos. La forma de evitar esto es no consultar la tabla, lo cual no es necesario que haga. Cambie su procedimiento a una función que devuelva el resultado correcto dada una fecha de nacimiento:

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;

Observe una vez más que estoy usando months_between() funcionan ya que no todos los años tienen 365 días.

En su activador, asigna el valor directamente a la columna.

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

El :new.<column> la sintaxis es una referencia al <column> que se está actualizando. En este caso :new.age es el valor real que se va a poner en la tabla.

Esto significa que su tabla se actualizará automáticamente, que es el objetivo de un activador DML.

Como puede ver, la función tiene poco sentido; tu disparador puede volverse

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; 

Sin embargo, dicho esto, si va a utilizar esta función en otra parte de la base de datos, manténgala separada. Es una buena práctica mantener el código que se usa en varios lugares en una función como esta para que siempre se use de la misma manera. También garantiza que cada vez que alguien calcule la edad, lo hará correctamente.

Como un pequeño aparte, ¿estás seguro de que quieres permitir que las personas tengan 9,999 años? O 0.000000000001998 (prueba)? La precisión numérica se basa en el número de significativos dígitos; esto (según Oracle) es distinto de cero solo numeros. Esto te puede atrapar fácilmente. El objetivo de una base de datos es restringir los posibles valores de entrada solo a aquellos que son válidos. Consideraría seriamente declarar su columna de edad como number(3,0) para garantizar que solo se incluyan valores "posibles".