我一直在使用各种约束在oracle中试验触发器功能,最近有人建议我在以下条件下使用物化视图而不是触发器,我认为这是一个明智的选择。但出于学习目的,我想知道触发功能是如何工作的。
创建一个触发器,以按月检查指定约束。
表租
|ID|Member|book|
----------------------
1 | John |fairytale|2-jun-12|
2 | Peter |friction|4-jun-12|
3 | John |comic|12-jun-12|
4 | Peter |magazine|20-jun-12|
5 | Peter |magazine|20-jul-12|
6 | Peter |magazine|20-jul-12|
约束:会员每月只允许借2本书。
由@HiltoN提供的代码,我不太明白:
create or replace trigger tr_rent
before insert on rent
for each row
declare
v_count number;
begin
select count(id)
into v_count
from rent
where member = :new.member;
if v_count > 2 then
raise_application_error (-20001, 'Limit reached');
end if;
end;
答案 0 :(得分:1)
通常,该触发器不起作用。
通常,表X上的行级触发器无法查询表X.因此,在您的情况下,RENT
上的行级触发器通常不允许查询RENT
表 - - 这样做会抛出一个变异触发器异常。如果您想保证您的应用程序只使用INSERT ... VALUES
语句一次插入一行,您将不会遇到变异触发错误,但这通常不是一个合适的限制。它在多用户环境中也是不合适的 - 如果有两个事务几乎同时运行同时向同一个用户签出一本书,则此触发器可能会使两个事务都成功。
添加此类检查的正确位置几乎可以肯定在创建RENT
记录的存储过程中。该存储过程应该检查该成员在当前月份的租金数量,如果超过限制则出错。像
CREATE OR REPLACE PROCEDURE rent_book( p_member IN rent.member%type,
p_book IN rent.book%type )
AS
l_max_rentals_per_month constant number := 2;
type rental_nt is table of rent.rend_id%type;
l_rentals_this_month rental_nt;
BEGIN
SELECT rent_id
BULK COLLECT INTO l_rentals_this_month
FROM rent
WHERE member = p_member
AND trunc(rental_date,'MM') = trunc(sysdate, 'MM')
FOR UPDATE;
IF( l_rentals_this_month.count > l_max_rentals_per_month )
THEN
RAISE_APPLICATION_ERROR( -20001, 'Rental limit exceeded' );
ELSE
INSERT INTO rent( rent_id, member, book, rental_date )
VALUES( rent_id_seq.nextval, p_member, p_book, sysdate );
END IF;
END;
如果您真的想使用触发器强制执行此类操作,则解决方案将变得更加复杂。如果您不关心效率,可以创建语句级触发器
create or replace trigger tr_rent
after insert on rent
declare
v_count number;
begin
select count(id)
into v_count
from (select member, count(*)
from rent
where trunc(rental_date,'MM') = trunc(sysdate,'MM')
group by member
having count(*) > 2);
if v_count >= 1 then
raise_application_error (-20001, 'At least one person has exceeded their rental limit');
end if;
end;
这有效,但它(至少)要求您每次都为每个成员进行验证。当你有大量的成员时,这是非常低效的。您可以通过大幅增加复杂性来减少工作量。如果你
rent.member%type
。:new.member
添加到此集合member
在您正在维护的集合中的附加条件。这种“三触发解决方案”为系统增加了大量复杂性,特别是在适当的解决方案不首先使用触发器的情况下。
答案 1 :(得分:0)
我同意贾斯汀的说法,你的触发器因多种原因无效。物化视图或存储过程解决方案可以帮助您实现目标。我建议这个问题的最佳解决方案是一个简单的唯一索引:
create unique index rent_user_limit on rent (member, trunc(rental_date, 'month'));