一般来说,触发不起作用。
一般情况下,在表X行级触发器不能查询表X.那么,在你的情况下,RENT
行级触发器一般是不允许查询RENT
table--这样做会抛出一个不同诱变触发异常。如果您希望保证您的应用程序只使用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
的集合。
- 创建一个用于初始化此集合的before语句触发器。
- 创建一个行级触发器,增加了
:new.member
到此集合
- 创建语句之后触发类似于上面的一个,但有一个附加条件,即
member
是你保持集中。
这种“三触发解决方案”为系统增加了大量的复杂性,尤其是在适当的解决方案首先不使用触发器的情况下。
可能重复http://stackoverflow.com/questions/13349350/oracle-trigger-that-check-constraint-on-a-monthly) – shellter