我有一张table
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;
/
3条答案
按热度按时间bakd9h0s1#
请帮帮我,我真的需要这个。
不你不知道我不确定你会注意听没有理由你应该:-)但是:
**不要在数据库中存储年龄。**你绝对保证偶尔会出错。每个人的年龄每年都在变化,但有些人的年龄每天都在变化。这反过来意味着您需要每天运行一个批处理作业并更新年龄。如果这失败了,或者不是 * 非常严格 *,并且运行了两次,那么你就有麻烦了。
你应该 * 总是 * 计算年龄时,你需要它。这是一个相当简单的查询,从长远来看,可以为您节省很多麻烦。
我设置了一个小SQL Fiddle来演示
现在,为了回答你的问题
这个过程工作正常,但只有一行,但对于所有的行,我需要触发器,但如果我从一个触发器调用它,然后发生错误.
你没有提到错误,请在未来这样做,因为它是非常有帮助的,但我怀疑你得到
ORA-04091:表字符串。字符串正在发生变化,触发器/函数可能看不到它
这是因为您的过程正在查询正在更新的表。Oracle不允许这样做,以便维护数据的读一致性视图。避免这种情况的方法是不查询表,您不需要这样做。将您的过程更改为一个函数,该函数将返回给定出生日期的正确结果:
请再次注意,我使用的是
months_between()
函数,因为并非所有年份都有365天。然后在触发器中将值直接赋给列。
:new.<column>
语法是对正在更新的<column>
的引用。在这种情况下,:new.age
是要放入表中的实际值。这意味着您的表将自动更新,这是DML触发器的点。
正如你所看到的,这个函数没有什么意义;你的触发器会变成
然而,话虽如此,如果你要在数据库的其他地方使用这个函数,那么就把它分开。将在多个地方使用的代码保存在这样的函数中是一个很好的做法,这样它就总是以相同的方式使用。它还确保任何人计算年龄时都能正确地计算。
顺便说一句,你确定你想让人们活到9,999岁吗?或者0.00000000001998(证明)?数值精度基于 * 有效 * 位数;这(根据Oracle)是 * 非零 * 数字。你很容易被这个抓住。数据库的意义在于将可能的输入值限制为只有那些有效的值。我会认真考虑将您的age列声明为
number(3,0)
,以确保只包含“可能”的值。e4yzc0pl2#
如果你通过一个触发器来做,那么一天后年龄可能就错了。这就是为什么在数据库表中保存年龄是一个不好的做法,没有人这样做。你需要的是风景。
查看SQL Fiddle
zqdjd7g93#
如果您希望AGE从数据库中可用,则有两个选项:
1.定义一个包含年龄计算的视图,或者
1.定义一个执行相同操作的虚拟列
要定义此类视图,请执行以下操作:
这样做的问题是,你必须记住,你从DATES_VIEW选择,但需要更新DATES,这是精神混乱。IMO向表中添加虚拟列更简洁:
请注意,虚拟列无法更新。
这两种方法都有助于确保AGE始终保持一致。