请帮忙...我真的需要这个...
不,你没有。我不确定你会注意;而且你没有理由应该:-)但是:
不要将年龄存储在您的数据库中。绝对保证您偶尔会出错。每个人的年龄每年都在变化,但是,对于某些人来说,它每天都在变化。这反过来意味着您需要每天运行批处理作业并更新年龄。如果这失败了,或者不是非常严格并且运行了两次,那么你就有麻烦了。
您应该始终在需要时计算年龄。这是一个相当简单的查询,从长远来看可以为您省去很多麻烦。
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 是要放入表中的实际值。
这意味着您的表格将自动更新,即the point of a DML trigger。
正如您所见,该功能根本没有意义;你的触发器可以变成
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 (proof)? Numeric precision 基于有效位数;这(根据 Oracle)只是 非零 数字。你很容易被这个抓住。数据库的重点是将可能的输入值限制为仅有效的输入值。我会认真考虑将您的年龄列声明为number(3,0),以确保仅包含“可能”的值。