したがって、例2のテーブルがあります。
movies
:
mid
-pk varchar2MovieName
-varchar2outstanding
-数値rental
:
sid
-数値pkmid
-fk varchar2rent_out
-日付rent_in
-日付movies.outstanding
が入力されたときにrental.rent_in
の値を減らすトリガーが必要です。
トリガーでこのようなものを書いてみました
outstanding = outstanding - 1
when mid = old.mid
しかし、トリガーが発火すると、代わりに数を増やして減らします。各行と更新後に使用しました。これで助けが必要です。
レンタルテーブルを更新する最初のトリガーは次のとおりです。
create or replace
trigger rentals_rent_trg
after insert on rentals
for each row
begin
update Movies
set outstanding = outstanding + 1
where mid = :new.mid;
end;
2番目のトリガーについてサポートが必要です。これは私の2番目のトリガーです。正しくありません。いくつか試しましたが、機能しません。
create or replace
trigger rentals_return_trg
after update of return_date on rentals
for each row
begin
update Movies
set outstanding = outstanding - 1
where :old.mid = :old.mid;
end;
このように2番目のトリガーを書き込もうとすると、ORA-04091を受け取ります。RENTALSが変化し、トリガー/関数がそれを認識しない場合があります。
create or replace
trigger rentals_return_trg
after update of return_date on rentals
for each row
declare
return_date_temp date;
begin
select return_date
into return_date_temp
from rentals
where return_date = :new.return_date
and return_date is not null;
if return_date_temp is not null
then
update Movies
set outstanding = outstanding - 1
where mid = :new.mid ;
/*mid = :old.mid;*/
end if;
end;
そのエラーが発生したため、compundトリガーを作成しましたが、今は数を減らすことができましたが、代わりに行に基づいています::old.outstanding = 5の場合、1桁下がるだけなので、実際の実行に基づいています:new.outstanding = 4.私は本当に助けが必要です笑。
create or replace trigger rentals_return_trg
FOR update of return_date on rentals
COMPOUND TRIGGER
cursor return_date_cur is
select R.rid, R.mid, R.return_date, M.outstanding
from rentals R JOIN MOVIES M
ON R.mid = M.mid;
type return_typ is table of return_date_cur%ROWTYPE
index by binary_integer;
return_tbl return_typ;
INT number(4) := 0;
BEFORE STATEMENT IS
begin
for rec in return_date_cur loop
int := int +1;
return_tbl(int).rid := rec.rid;
return_tbl(int).mid := rec.mid;
return_tbl(int).return_date := rec.return_date;
return_tbl(int).outstanding := rec.outstanding;
end loop;
END BEFORE STATEMENT;
AFTER EACH ROW IS
LV_RETURN_DT DATE;
LV_OUTSTANDING_NUM NUMBER;
BEGIN
for i IN 1..return_tbl.count loop
if return_tbl(i).return_date = :NEW.return_date THEN
LV_OUTSTANDING_NUM := return_tbl(i).outstanding - i;
exit;
end if;
end loop;
if :new.return_date is not null then
update movies
set outstanding = LV_OUTSTANDING_NUM;
end if;
end after each row;
end;
Oracle 12cを使用して、手順をもう一度たどってみました。 2番目のトリガーにはいくつかの変更が必要です...
テスト設定:
create table movies (
mid varchar2(64) primary key
, MovieName varchar2(64)
, outstanding number
);
create table rentals(
sid number primary key
, mid varchar2(64) references movies(mid)
, rent_out date
, rent_in date
) ;
-- original trigger -> okay, works for INSERTs
create or replace
trigger rentals_rent_trg
after insert on rentals
for each row
begin
update Movies
set outstanding = outstanding + 1
where mid = :new.mid;
end;
/
テストデータ(挿入):
insert into movies (mid, moviename, outstanding)
values (1, 'Snatch', 0);
insert into movies (mid, moviename, outstanding)
values (2, 'Aliens', 0);
insert into movies (mid, moviename, outstanding)
values (3, 'Mars', 0);
-- check
select * from movies;
SQL> select * from movies;
MID MOVIENAME OUTSTANDING
1 Snatch 0
2 Aliens 0
3 Mars 0
-- table RENTALS: insert 42 rows for movies 1 and 2
begin
for i in 1 .. 42
loop
insert into rentals (sid, mid, rent_out, rent_in)
values (i+100,1,'19-AUG-2017',null);
insert into rentals (sid, mid, rent_out, rent_in)
values (i+200,2,'20-AUG-2017',null);
end loop;
end;
/
-- checks
SQL> select count(*) from rentals;
COUNT(*)
84
SQL> select * from movies;
MID MOVIENAME OUTSTANDING
1 Snatch 42
2 Aliens 42
3 Mars 0
小さな変更を加えた2番目のトリガーを使用してみましょう。
create or replace
trigger rentals_return_trg
after update of rent_in on rentals
for each row
declare
new_ number default 0 ;
begin
new_ := :new.mid ;
update Movies
set outstanding = outstanding - 1
where mid = new_;
end;
/
Trigger RENTALS_RETURN_TRG compiled
ここで、「rentals」テーブルの一部の行を更新し、それぞれ「movies」と「rentals」を確認すると、すべてが期待通りに機能しているように見えます(影響を受ける行のみが選択されます)この例ではレンタルから)。
-- "Aliens" and "Mars" not affected
begin
for i in 120 .. 125
loop
update rentals
set rent_in = '22-AUG-2017'
where sid = i ;
end loop;
end;
/
SQL> select * from rentals where rent_in is not null;
SID MID RENT_OUT RENT_IN
120 1 19-AUG-17 22-AUG-17
121 1 19-AUG-17 22-AUG-17
122 1 19-AUG-17 22-AUG-17
123 1 19-AUG-17 22-AUG-17
124 1 19-AUG-17 22-AUG-17
125 1 19-AUG-17 22-AUG-17
SQL> select * from movies;
MID MOVIENAME OUTSTANDING
1 Snatch 36
2 Aliens 42
3 Mars 0
これは、トリガーよりも「RentMovie」の手順の方が適しているようです。あまりに頻繁に行うと、少し面倒になる可能性があります。
したがって、「RentMovie」手順では次のようになります。
または、movie.Outstanding updateを独自のプロシージャに分離し、代わりにそのように呼び出すこともできます。
同じ手順で値の増分も処理できることに注意してください(逆のシナリオ)。