Oracle trigger that check constraint on a monthly basis

五迷三道 提交于 2019-12-04 05:25:10

问题


just wonder is it possible to create a trigger to check on a specify constraint base on monthly basis.

eg.
table rent
|ID|Member|book|
----------------------
1 | John |fairytale|

2 | John |friction|

3 | John |comic|

4 | John |magazine|

constraint : member are only allow to borrow 4 books monthly.

i thought of using count(book) <= 4 but does not know how to implement the monthly basis constraint.

Any suggestion?


回答1:


using a trigger, whilst it seems to work, is a dangerous way of doing it, as sessions running in parallel wont see the inserted data from the inprogress session. you can do it via a materilized view:

SQL> create table rent (id number primary key, member varchar2(30), book varchar2(20), date_rented date);

Table created.

SQL> create index rent_ix1 on rent ( member, date_rented);

Index created.

SQL> create materialized view log on rent with rowid(member,date_rented)
  2  including new values;

Materialized view log created.

SQL> create materialized view rent_month_check
  2  refresh fast on commit
  3  as
  4  select trunc(date_rented, 'mm') month, member, count(*) rentals
  5    from rent
  6   group by trunc(date_rented, 'mm'), member;

Materialized view created.

SQL> alter table rent_month_check
  2  add constraint rent_month_check_ck1 check (rentals <= 4);

Table altered.

SQL> insert into rent values(1, 'DazzaL', 'crime', sysdate);

1 row created.

SQL> commit;

Commit complete.

SQL> insert into rent values(2, 'DazzaL', 'mystery', sysdate+1);

1 row created.

SQL> commit;

Commit complete.

SQL> insert into rent values(3, 'DazzaL', 'fantasy', sysdate+2);

1 row created.

SQL> commit;

Commit complete.

SQL> insert into rent values(4, 'DazzaL', 'politics', sysdate+3);

1 row created.

SQL> commit;

Commit complete.

SQL> insert into rent values(5, 'DazzaL', 'thriller', sysdate+4);

1 row created.

SQL> commit;
commit
*
ERROR at line 1:
ORA-12008: error in materialized view refresh path
ORA-02290: check constraint (TEST.RENT_MONTH_CHECK_CK1) violated


SQL> select * from rent_month_check;

MONTH     MEMBER                            RENTALS
--------- ------------------------------ ----------
01-NOV-12 DazzaL                                  4



回答2:


If the table stores only actual data then it is quite simple:

create or replace trigger tr_rent
before insert on rent
for each row 
declare
  v_count number;
begin
  select count(*) into v_count
  from rent where member = :new.member;

  if v_count >= 4 then
    raise_application_error(-20001, 'Limit reached');
  end if;
end;
/

But if the table store historical data as well then you need some timestamp column, f.e. rent_date. So the count-query should be changed to the following:

select count(*) into v_count
from rent where member = :new.member
and rent_date > add_months(sysdate, -1);

In some cases reading a table that is currently being modified may lead to "mutating table error", but the trigger above is safe.



来源:https://stackoverflow.com/questions/13349350/oracle-trigger-that-check-constraint-on-a-monthly-basis

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!