使用oracle plsql触发器计算生日年龄并在表中插入年龄

hit*_*047 3 sql database oracle triggers plsql

我有一张桌子

dates
(dob date,
age number(4)
);
Run Code Online (Sandbox Code Playgroud)

我将插入一个出生日期,触发器将计算年龄并在年龄字段中插入该年龄.

CREATE OR REPLACE PROCEDURE getage IS 
ndob date;
nage number(10);
BEGIN
select dob into ndob from dates; 
select (sysdate-to_date(ndob))/365 into nage from dual;
update dates set age=nage;
END;
/
SHOW ERRORS;
Run Code Online (Sandbox Code Playgroud)

这个过程工作正常,但只有一行,我需要触发所有行,但如果我从触发器调用它,则会发生错误.

CREATE OR REPLACE TRIGGER agec after INSERT OR UPDATE ON dates
FOR EACH ROW
BEGIN
getage;
END; 
/
Run Code Online (Sandbox Code Playgroud)

Ben*_*Ben 8

请帮忙......我真的需要这个......

不,你没有.我不确定你会注意; 并且没有理由你应该:-)但是:

不要在数据库中存储年龄.绝对保证你偶尔会犯错.每个人每年的年龄都会发生变化,但是,对于某些人来说,每天都会发生变化.这反过来意味着您需要每天运行批处理作业并更新年龄.如果这个失败,或者不是非常严格并且运行两次,那你就麻烦了.

您应该随时根据需要计算年龄.这是一个相当简单的查询,从长远来看可以为您节省很多痛苦.

select floor(months_between(sysdate,<dob>)/12) from dual
Run Code Online (Sandbox Code Playgroud)

我已经设置了一个小小的SQL小提琴来演示


现在,实际回答你的问题

这个程序工作正常,但只有一行,,,但对于我需要触发的所有行,但如果我从触发器调用它,那么错误发生...

你没有提到错误,请在将来这样做,因为它非常有帮助,但我怀疑你得到了

ORA-04091:表string.string正在变异,触发器/函数可能看不到它

这是因为您的过程正在查询正在更新的表.Oracle不允许这样做以保持数据的读一致视图.避免这种情况的方法是不查询表,您不需要这样做.将您的程序更改为在出生日期返回正确结果的函数:

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;
Run Code Online (Sandbox Code Playgroud)

再次注意我正在使用该months_between()功能,因为并非所有年份都有365天.

在触发器中,然后将值直接分配给列.

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

:new.<column>语法是对<column>正在更新的语法的引用.在这种情况下:new.age,将是放在表中的实际值.

这意味着您的表将自动更新,这是DML触发器的重点.

正如你所看到的那样,功能根本没什么意义; 你的触发器可以成为

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; 
Run Code Online (Sandbox Code Playgroud)

但是,话虽如此,如果您打算在数据库的其他地方使用此功能,请将其分开.在这样的函数中保留在多个位置使用的代码是一种很好的做法,因此它总是以相同的方式使用.它还确保无论何时任何人计算年龄,他们都会正确地做到这一点.

稍微放在一边,你确定你想让人们成为9,999岁吗?或0.000000000001998 (证明)数字精度基于有效位数; 这(根据Oracle)仅为非零数字.你很容易被这个抓住.数据库的要点是将可能的输入值限制为仅有效的输入值.我会认真考虑宣布您的年龄列,number(3,0)以确保只包含"可能"的值.