Oracle Database
Aggiorna con Joins
Ricerca…
introduzione
Esempi: cosa funziona e cosa no
create table tgt ( id, val ) as
select 1, 'a' from dual union all
select 2, 'b' from dual
;
Table TGT created.
create table src ( id, val ) as
select 1, 'x' from dual union all
select 2, 'y' from dual
;
Table SRC created.
update
( select t.val as t_val, s.val as s_val
from tgt t inner join src s on t.id = s.id
)
set t_val = s_val
;
SQL Error: ORA-01779: cannot modify a column which maps to a non key-preserved table
01779. 00000 - "cannot modify a column which maps to a non key-preserved table"
*Cause: An attempt was made to insert or update columns of a join view which
map to a non-key-preserved table.
*Action: Modify the underlying base tables directly.
Immagina cosa succederebbe se avessimo il valore 1
nella colonna src.id
più di una volta, con valori diversi per src.val
. Ovviamente, l'aggiornamento non avrebbe senso (in QUALSIASI database - questo è un problema logico). Ora, sappiamo che non ci sono duplicati in src.id
, ma il motore di Oracle non sa che - quindi è lamentarsi. Forse è questo il motivo per cui così tanti professionisti credono che Oracle "non abbia UPDATE con join"?
Quello che Oracle si aspetta è che src.id
dovrebbe essere unico e che, Oracle, lo saprebbe in anticipo. Facilmente risolto! Si noti che lo stesso funziona con i tasti compositi (su più di una colonna), se la corrispondenza per l'aggiornamento deve utilizzare più di una colonna. In pratica, src.id
potrebbe essere PK e tgt.id
potrebbe essere FK che punta a questo PK, ma questo non è rilevante per gli aggiornamenti con join; ciò che è rilevante è il vincolo univoco.
alter table src add constraint src_uc unique (id);
Table SRC altered.
update
( select t.val as t_val, s.val as s_val
from tgt t inner join src s on t.id = s.id
)
set t_val = s_val
;
2 rows updated.
select * from tgt;
ID VAL
-- ---
1 x
2 y
Lo stesso risultato potrebbe essere ottenuto con una dichiarazione MERGE (che merita il proprio articolo di documentazione) e personalmente preferisco MERGE in questi casi, ma la ragione non è che "Oracle non aggiorni gli aggiornamenti con join". Come mostra questo esempio, Oracle esegue aggiornamenti con join.