他のほとんどの人が示しているように、データ モデルが原因で大きな問題が発生しています。このモデル用に書かれたほとんどのコードは、必要以上に難しくなります。私は賛成票と反対票を投じて、またいくつかのコメントでもそれを言いましたが、十分に言うことはできません.
パスを続行する場合、以下のコードは何をする必要があるかを示しています。うまくいけば、それはあなたを怖がらせます:-)
サンプル テーブル:
SQL> create table vehicles (id,registrationnumber,lastallocationusername,lastallocationdate,lastallocationid)
2 as
3 select 1, 1, 'Me', sysdate-1, 2 from dual union all
4 select 2, 2, 'Me', sysdate, 3 from dual
5 /
Table created.
SQL> create table allocations (id,vehicleid,username,mydate)
2 as
3 select 1, 1, 'Me', sysdate-2 from dual union all
4 select 2, 1, 'Me', sysdate-1 from dual union all
5 select 3, 2, 'Me', sysdate-1 from dual
6 /
Table created.
トリガーは、最後の割り当てを決定するために、独自のテーブルを調べる必要があります。Oracle は、変更テーブル エラーを発生させることにより、このタイプのダーティ リードを防止します。これを回避するために、SQL 型とパッケージを作成します。
SQL> create type t_vehicle_ids is table of number;
2 /
Type created.
SQL> create package allocations_mutating_table
2 as
3 procedure reset_vehicleids;
4 procedure store_vehicleid (p_vehicle_id in vehicles.id%type);
5 procedure adjust_vehicle_last_allocation;
6 end allocations_mutating_table;
7 /
Package created.
SQL> create package body allocations_mutating_table
2 as
3 g_vehicle_ids t_vehicle_ids := t_vehicle_ids()
4 ;
5 procedure reset_vehicleids
6 is
7 begin
8 g_vehicle_ids.delete;
9 end reset_vehicleids
10 ;
11 procedure store_vehicleid (p_vehicle_id in vehicles.id%type)
12 is
13 begin
14 g_vehicle_ids.extend;
15 g_vehicle_ids(g_vehicle_ids.count) := p_vehicle_id;
16 end store_vehicleid
17 ;
18 procedure adjust_vehicle_last_allocation
19 is
20 begin
21 update vehicles v
22 set ( v.lastallocationusername
23 , v.lastallocationdate
24 , v.lastallocationid
25 ) =
26 ( select max(a.username) keep (dense_rank last order by a.mydate)
27 , max(a.mydate)
28 , max(a.id) keep (dense_rank last order by a.mydate)
29 from allocations a
30 where a.vehicleid = v.id
31 )
32 where v.id in (select column_value from table(cast(g_vehicle_ids as t_vehicle_ids)))
33 ;
34 end adjust_vehicle_last_allocation
35 ;
36 end allocations_mutating_table;
37 /
Package body created.
次に、3 つのデータベース トリガーを使用して、更新コードを行レベルからステートメント レベルに移動し、変更テーブル エラーを回避します。
SQL> create trigger allocations_bsiud
2 before insert or update or delete on allocations
3 begin
4 allocations_mutating_table.reset_vehicleids;
5 end;
6 /
Trigger created.
SQL> create trigger allocations_ariud
2 after insert or update or delete on allocations
3 for each row
4 begin
5 allocations_mutating_table.store_vehicleid(nvl(:new.vehicleid,:old.vehicleid));
6 end;
7 /
Trigger created.
SQL> create trigger allocations_asiud
2 after insert or update or delete on allocations
3 begin
4 allocations_mutating_table.adjust_vehicle_last_allocation;
5 end;
6 /
Trigger created.
そして、単一ユーザー環境で動作することを確認するための簡単なテスト:
SQL> select * from vehicles
2 /
ID REGISTRATIONNUMBER LA LASTALLOCATIONDATE LASTALLOCATIONID
---------- ------------------ -- ------------------- ----------------
1 1 Me 13-05-2010 14:03:43 2
2 2 Me 14-05-2010 14:03:43 3
2 rows selected.
SQL> insert into allocations values (4, 1, 'Me', sysdate)
2 /
1 row created.
SQL> select * from vehicles
2 /
ID REGISTRATIONNUMBER LA LASTALLOCATIONDATE LASTALLOCATIONID
---------- ------------------ -- ------------------- ----------------
1 1 Me 14-05-2010 14:03:43 4
2 2 Me 14-05-2010 14:03:43 3
2 rows selected.
SQL> update allocations
2 set mydate = mydate - 2
3 where id = 4
4 /
1 row updated.
SQL> select * from vehicles
2 /
ID REGISTRATIONNUMBER LA LASTALLOCATIONDATE LASTALLOCATIONID
---------- ------------------ -- ------------------- ----------------
1 1 Me 13-05-2010 14:03:43 2
2 2 Me 14-05-2010 14:03:43 3
2 rows selected.
SQL> delete allocations
2 where id in (2,4)
3 /
2 rows deleted.
SQL> select * from vehicles
2 /
ID REGISTRATIONNUMBER LA LASTALLOCATIONDATE LASTALLOCATIONID
---------- ------------------ -- ------------------- ----------------
1 1 Me 12-05-2010 14:03:43 1
2 2 Me 14-05-2010 14:03:43 3
2 rows selected.
あとは、シリアライゼーションを追加して、マルチ ユーザー環境で 100% 動作させるだけです。しかし、うまくいけば、この例はそのままで十分に恐ろしいものでした.
よろしく、ロブ。