I'm trying to create an updatable view between two Oracle tables which have exactly the same key structure. The existing tables are created by an ERP system and:
- Do not have primary keys - only a unique index.
- All fields are non-null, but one of the composite index fields is descending.
Is there any way I can create an updatable view across these two tables?
The real tables concerned contain a lot of data and are heavily used, so any changes / additions to the indexes would require significant regression testing, so I need to confine any solution to the view itself.
Problem seems to be something to do with Oracle creating separate composite function based indexes for the descending KEY2 fields. I've tried throwing a few hints into the view but am out of my depth here, and really not much idea what I'm doing.
Here's a simplified example. If I remove the "desc" from the two KEY2 index fields the final update works - if I leave it in it fails with: "ORA-01779: cannot modify a column which maps to a non key-preserved table".
create table TEST_KEY_PRES_A (
KEY1 varchar2(8) not null,
KEY2 varchar2(8) not null,
VAL1 smallint not null,
VAL2 varchar2(8) not null
)
;
create unique index TEST_KEY_PRES_A_IDX
on TEST_KEY_PRES_A (KEY1, KEY2 desc)
;
insert into TEST_KEY_PRES_A values ('K11', 'K21', 1, 'V2-1');
insert into TEST_KEY_PRES_A values ('K15', 'K25', 5, 'V2-5');
create table TEST_KEY_PRES_B (
KEY1 varchar2(8) not null,
KEY2 varchar2(8) not null,
VAL3 varchar2(8) not null
)
;
create unique index TEST_KEY_PRES_B_IDX
on TEST_KEY_PRES_B (KEY1, KEY2 desc)
;
insert into TEST_KEY_PRES_B values ('K11', 'K21', 'V3-1');
insert into TEST_KEY_PRES_B values ('K15', 'K25', 'V3-5');
create view TEST_KEY_PRES_VW (KEY1, KEY2, VAL1, VAL2, VAL3) AS
select pa.KEY1, pa.KEY2, pa.VAL1, pa.VAL2, pb.VAL3
from TEST_KEY_PRES_A pa
join TEST_KEY_PRES_B pb on pa.KEY1 = pb.KEY1 and pa.KEY2 = pb.KEY2
where pa.VAL1 > 3
;
update TEST_KEY_PRES_VW
set VAL2 = 'V2-5-X'
where KEY1 = 'K15'
;
SOLVED
Using INSTEAD OF trigger as suggested by Eduard:
create or replace trigger TEST_KEY_PRES_VW_UPD_TR
instead of update on TEST_KEY_PRES_VW
for each row
begin
update TEST_KEY_PRES_A
set VAL1 = :new.VAL1, VAL2 = :new.VAL2
where KEY1 = :new.KEY1 and KEY2 = :new.KEY2;
update TEST_KEY_PRES_B
set VAL3 = :new.VAL3
where KEY1 = :new.KEY1 and KEY2 = :new.KEY2;
end;