一般來說,觸發不起作用。
一般情況下,在表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