有效的例子和無用的例子
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.
想象一下,如果我們在 src.id
列中的值 1
不止一次,src.val
的值不同,會發生什麼。顯然,更新沒有意義(在任何資料庫中 - 這是一個邏輯問題)。現在,我們知道 src.id
中沒有重複項,但 Oracle 引擎並不知道 - 所以它在抱怨。也許這就是為什麼這麼多從業者認為甲骨文“沒有加入 UPDATE”的原因?
Oracle 期望的是 src.id
應該是唯一的,並且它,Oracle,事先就會知道。輕鬆修復! 請注意,如果更新的匹配需要使用多個列,則同樣適用於複合鍵(在多個列上)。在實踐中,src.id
可能是 PK 而 tgt.id
可能是指向此 PK 的 FK,但這與使用 join 的更新無關; 什麼是相關的是唯一的約束。
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
使用 MERGE 語句可以獲得相同的結果(值得自己的文件文章),在這些情況下我個人更喜歡 MERGE,但原因並不是“Oracle 不會使用連線進行更新”。如此示例所示,Oracle 確實使用聯接進行更新。