Как указывает большинство других: у вас большая проблема из-за вашей модели данных. Большая часть кода, написанного для этой модели, будет намного сложнее, чем нужно. Я говорил об этом и в голосах, и в некоторых комментариях, но этого недостаточно.
Если вы продолжите свой путь, то приведенный ниже код демонстрирует, что нужно сделать. Надеюсь, это вас пугает: -)
Образцы таблиц:
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.
Затем три триггера базы данных перемещают код обновления с уровня строки на уровень оператора, что позволяет обойти ошибку изменяющейся таблицы:
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% в многопользовательской среде. Но, надеюсь, пример был достаточно страшным.
С уважением,
Роб.