I’ve been experimenting trigger function in oracle with various constraint, recently someone recommends me to using materialized view instead of trigger on the following condition which i think is quite a wise choice to do so. But for learning purpose, i would like to know how does trigger function works.
create a trigger to check on a specify constraint base on monthly basis.
table rent
|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|
constraint : member are only allow to borrow 2 books monthly.
Code contributed by @HiltoN which i don’t quite understand:
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;
In general, that trigger does not work.
In general, a row-level trigger on table X cannot query table X. So, in your case, a row-level trigger on
RENTis generally not allowed to query theRENTtable– doing so would throw a mutating trigger exception. If you want to guarantee that your application will only ever insert 1 row at a time using anINSERT ... VALUESstatement, you won’t hit a mutating trigger error but that is generally not an appropriate restriction. It is also not appropriate in a multi-user environment– if there are two transactions running at about the same time both checking out a book to the same user, this trigger will potentially allow both transactions to succeed.The proper place to add this sort of check is almost certainly in the stored procedure that creates the
RENTrecord. That stored procedure should check how many rentals the member has over the current month and error out if that is more than the limit. Something likeIf you really wanted to enforce something like this using triggers, the solution would get much more complicated. If you don’t care about efficiency, you could create a statement-level trigger
This works but it requires (at least) that you do the validation for every member every time. That is pretty inefficient when you have a large number of members. You could reduce the workload by substantially increasing complexity. If you
rent.member%type.:new.memberto this collectionmemberis in the collection you’re maintaining.This “three-trigger solution” adds a substantial amount of complexity to the system particularly where the appropriate solution is not to use a trigger in the first place.