I have the following situation in a table with two date columns, Start_DT
and End_DT
.
+----+------------+------------+
| ID | Start_DT | End_DT |
+----+------------+------------+
| 1 | 01-01-2012 | 02-01-2012 |
| 2 | 02-01-2012 | 05-02-2012 |
| 3 | 05-02-2012 | 07-02-2012 |
+----+------------+------------+
Whenever I'm inserting a new row, for example I want to insert the following tuple ('06-02-2012', '10-02-2012')
, the End_DT
of the last (previous) row in chronological order, will be updated with the Start_DT
of the row I'm trying to insert, if there is a chronological overlap.
So, in the end, after inserting my new row, the table will look like:
+----+------------+------------+
| ID | Start_DT | End_DT |
+----+------------+------------+
| 1 | 01-01-2012 | 02-01-2012 |
| 2 | 02-01-2012 | 05-02-2012 |
| 3 | 05-02-2012 | 06-02-2012 |
| 4 | 06-02-2012 | 10-02-2012 |
+----+------------+------------+
The problem is that the trigger I've created is giving me an error, which I understand giving the way I've written my trigger, but I don't know how to modify it in order to achieve what I want:
SQL Error: ORA-04091: table HISTORIC_TIME_TABLE is mutating, trigger/function may not see it
We considered that it is mandatory to use SELECT FOR UDPATE
in order to put a lock on the previous row, in order to make the update. But changing this trigger into a AFTER
, I'm not sure if we can achieve the same lock on the table.
My trigger's code is:
create or replace trigger trg_update_historic_time_table
before insert on HISTORIC_TIME_TABLE
for each row
declare
cursor upd_hist_tt_cur
is
select start_dt, end_dt
from HISTORIC_TIME_TABLE
where (end_dt > sysdate)
for update of end_dt;
begin
for hist_cur_r in upd_hist_tt_cur loop
if hist_cur_r.start_dt < :new.start_dt then
update HISTORIC_TIME_TABLE
set end_dt = :new.start_dt
where (start_dt = hist_cur_r.start_dt);
commit;
else
:new.end_dt := hist_cur_r.start_dt;
end if;
end loop;
exception when no_data_found then null;
end;
I have found online on the Oracle docs page that BEFORE triggers cannot modify data in the same table:
Before triggers cannot have INSERT, UPDATE or DELETE statements as their action.
Before triggers cannot call procedures that modify SQL data as their action.
So, I'm thinking about modifying my trigger to a AFTER
type, but then I wouldn't have access to my :new
and :old
variables.
Any help is greatly appreciated.