Oracle trigger that check constraint on a monthly basis

前端 未结 2 892
灰色年华
灰色年华 2021-01-23 14:20

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|
-------------

相关标签:
2条回答
  • 2021-01-23 14:43

    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
    
    0 讨论(0)
  • 2021-01-23 14:51

    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.

    0 讨论(0)
提交回复
热议问题