有效的例子和无用的例子
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 确实使用联接进行更新。