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)
请帮忙......我真的需要这个......
不,你没有.我不确定你会注意; 并且没有理由你应该:-)但是:
不要在数据库中存储年龄.绝对保证你偶尔会犯错.每个人每年的年龄都会发生变化,但是,对于某些人来说,每天都会发生变化.这反过来意味着您需要每天运行批处理作业并更新年龄.如果这个失败,或者不是非常严格并且运行两次,那你就麻烦了.
您应该随时根据需要计算年龄.这是一个相当简单的查询,从长远来看可以为您节省很多痛苦.
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)以确保只包含"可能"的值.