Ricerca…


introduzione

Contrariamente a diffusi fraintendimenti (anche su SO), Oracle consente aggiornamenti tramite join. Tuttavia, ci sono alcuni requisiti (piuttosto logici). Illustriamo cosa non funziona e cosa fa attraverso un semplice esempio. Un altro modo per ottenere lo stesso è la dichiarazione MERGE.

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.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow