dates (dob date,age number(4) );
我将插入一个出生日期,触发器将计算年龄并在年龄字段中插入该年龄.
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;
这个过程工作正常,但只有一行,我需要触发所有行,但如果我从触发器调用它,则会发生错误.
CREATE OR REPLACE TRIGGER agec after INSERT OR UPDATE ON dates FOR EACH ROW BEGIN getage; END; /
please help…i really need this…
不,你没有.我不确定你会注意;并且没有理由你应该:-)但是:
不要在数据库中存储年龄.你绝对保证偶尔会出错.每个人每年的年龄都会发生变化,但是,对于某些人来说,每天都会发生变化.这反过来意味着您需要每天运行批处理作业并更新年龄.如果这个失败,或者不是非常严格并且运行两次,那你就麻烦了.
您应该随时根据需要计算年龄.这是一个相当简单的查询,从长远来看可以为您节省很多痛苦.
select floor(months_between(sysdate,<dob>)/12) from dual
我已经设置了一个SQL Fiddle来演示
现在,实际回答你的问题
this procedure works fine but for only one row,but for all the rows
i need trigger but if i call it from a trigger then the error
occurs…
你没有提到错误,请在将来这样做,因为它非常有帮助,但我怀疑你得到了
ORA-04091: table string.string is mutating,trigger/function may not
see it
这是因为您的过程正在查询正在更新的表. 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)仅为非零数字.你很容易被这个抓住.数据库的要点是将可能的输入值限制为仅有效的输入值.我认真考虑将您的年龄列声明为数字(3,0)以确保仅包含“可能”值.