请帮助...我真的需要这个...
不,你没有。我不确定你会注意;而且你没有理由应该:-)但是:
不要将年龄存储在数据库中。你绝对保证偶尔会出错。每个人的年龄每年都在变化,但是,对于某些人来说,它每天都在变化。这反过来意味着您需要每天运行批处理作业并更新年龄。如果这失败了,或者不是非常严格并且运行了两次,那么你就有麻烦了。
您应该始终在需要时计算年龄。这是一个相当简单的查询,从长远来看可以为您节省很多痛苦。
select floor(months_between(sysdate,<dob>)/12) from dual
我设置了一个小SQL Fiddle来演示
现在,要真正回答你的问题
此过程工作正常,但仅适用于一行,但是对于我需要触发器的所有行,但如果我从触发器中调用它,则会发生错误......
你没有提到错误,请在以后这样做,因为它非常有帮助,但我怀疑你得到了
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;
请再次注意,我正在使用该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;
: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;
但是,话虽如此,如果您要在数据库的其他地方使用此功能,请将其分开。将在多个地方使用的代码保存在这样的函数中是一种很好的做法,因此它始终以相同的方式使用。它还确保无论何时任何人计算年龄,他们都会正确计算。
顺便说一句,您确定要让人们活到 9,999 岁吗?还是 0.000000000001998 (证明)?数值精度基于有效位数;这(根据 Oracle)只是非零数字。你很容易被这个抓住。数据库的重点是将可能的输入值限制为仅有效的输入值。我会认真考虑声明您的年龄列,number(3,0)
以确保仅包含“可能”的值。