Szukaj…


Wprowadzenie

W przeciwieństwie do powszechnych nieporozumień (w tym dotyczących SO), Oracle zezwala na aktualizacje poprzez dołączenia. Istnieją jednak pewne (dość logiczne) wymagania. Ilustrujemy, co nie działa, a co działa na prostym przykładzie. Innym sposobem osiągnięcia tego samego jest instrukcja MERGE.

Przykłady: co działa, a co nie

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.

Wyobraź sobie, co by się stało, gdybyśmy mieli wartość 1 w kolumnie src.id więcej niż raz, z różnymi wartościami dla src.val . Oczywiście aktualizacja nie miałaby sensu (w DOWOLNEJ bazie danych - to logiczny problem). Teraz wiemy, że nie ma duplikatów w src.id , ale silnik Oracle nie wie, że - tak to jest sędzią. Być może dlatego tak wielu praktyków uważa, że Oracle „nie ma aktualizacji z połączeniami”?

Oracle oczekuje, że src.id powinien być unikalny, i że on, Oracle, będzie o tym wiedział wcześniej. Łatwo naprawione! Pamiętaj, że to samo działa z kluczami złożonymi (w więcej niż jednej kolumnie), jeśli dopasowanie dla aktualizacji wymaga użycia więcej niż jednej kolumny. W praktyce src.id może być PK, a tgt.id może oznaczać FK wskazujący na ten PK, ale nie dotyczy to aktualizacji z łączeniem; co jest istotne jest ograniczenie przez unikalność.

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

Ten sam wynik można osiągnąć za pomocą instrukcji MERGE (która zasługuje na własny artykuł z dokumentacji), a ja osobiście wolę MERGE w tych przypadkach, ale powodem nie jest to, że „Oracle nie dokonuje aktualizacji z łączeniami”. Jak pokazuje ten przykład, Oracle dokonuje aktualizacji z łączeniami.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow