月単位で特定の制約ベースをチェックするトリガーを作成することは可能でしょうか。
例えば。
テーブルレンタル
|ID|メンバー|本|
----------------------
1 | ジョン |おとぎ話|
2 | ジョン |フリクション|
3 | ジョン |コミック|
4 | ジョン |雑誌|
制約 : メンバーは毎月 4 冊までしか借りることができません。
count(book) <= 4 を使用することを考えましたが、月単位の制約を実装する方法がわかりません。
なにか提案を?
月単位で特定の制約ベースをチェックするトリガーを作成することは可能でしょうか。
例えば。
テーブルレンタル
|ID|メンバー|本|
----------------------
1 | ジョン |おとぎ話|
2 | ジョン |フリクション|
3 | ジョン |コミック|
4 | ジョン |雑誌|
制約 : メンバーは毎月 4 冊までしか借りることができません。
count(book) <= 4 を使用することを考えましたが、月単位の制約を実装する方法がわかりません。
なにか提案を?
テーブルに実際のデータのみが格納されている場合は、非常に簡単です。
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;
/
ただし、テーブルに履歴データも格納されている場合は、いくつかのタイムスタンプ列、ferent_date が必要です。そのため、count-query を次のように変更する必要があります。
select count(*) into v_count
from rent where member = :new.member
and rent_date > add_months(sysdate, -1);
場合によっては、現在変更中のテーブルを読み取ると「変更テーブル エラー」が発生する可能性がありますが、上記のトリガーは安全です。
トリガーを使用すると、機能しているように見えますが、並行して実行されているセッションでは進行中のセッションから挿入されたデータが表示されないため、危険な方法です。実体化されたビューを介してそれを行うことができます:
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