我对Oracle中(以及一般情况下)密钥保留的联接视图更新感到困惑;在使用带有连接的select进行更新时,是否应该为更新的表或嵌入式select语句保留键保留的属性。
在下面的示例中:
SQL> create table tabX (x1 number, x2 number);
Table created.
SQL> create table tabY (y1 number, y2 number);
Table created.
SQL> insert into tabx values (1,11);
1 row created.
SQL> insert into tabx values (2,12);
1 row created.
SQL> insert into taby values(1,21);
1 row created.
SQL> insert into taby values(2,22);
1 row created.
SQL> commit;
Commit complete.
select的输出是唯一的,但是更新仍然失败。选择和更新都没有歧义或重复-那么为什么会失败?
SQL> select x2,y2 from tabx,taby where tabx.x1=taby.y1;
X2 Y2
---------- ----------
11 21
12 22
SQL> update (select x2,y2 from tabx,taby where tabx.x1=taby.y1) set x2=y2;
update (select x2,y2 from tabx,taby where tabx.x1=taby.y1) set x2=y2
*
ERROR at line 1:
ORA-01779: cannot modify a column which maps to a non key-preserved table
答案 0 :(得分:1)
您知道没有重复,但是在分析该语句时,优化器并不知道没有重复,更重要的是,不可能。解析器查看统计信息以决定如何工作,但通常不查看数据。该update语句可能会被缓存和重用,因此,即使它看起来和现在都没有重复,但是稍后从缓存中再次运行同一条语句时,数据可能已更改。
想象一下,您增加了一行:
insert into taby values(2,222);
然后您的查询会得到:
select x2,y2 from tabx,taby where tabx.x1=taby.y1;
X2 Y2
---------- ----------
11 21
12 22
12 222
现在,更新具有两个可能的值来将两个x2=12
值都设置为;他们应该都是22岁,还是都是222岁,还是每个都之一? Oracle无法知道什么是正确的,并且无法选择应该使用前两个选项中的哪个(当然不能使用第三个)。
现在,这不是您的实际情况,但是您需要告诉Oracle无法发生这种情况。错误的措辞在这里暗示。为了使视图保留一个密钥,必须有一个密钥。如果您使用主键或唯一键定义tabY
:
create table tabY (y1 number primary key, y2 number);
insert into taby values(1,21);
insert into taby values(2,22);
然后不允许我伪造的第三个插入内容,Oracle知道了,可以将该知识应用于更新:
update (select x2,y2 from tabx,taby where tabx.x1=taby.y1) set x2=y2;
2 rows updated.
select x2,y2 from tabx,taby where tabx.x1=taby.y1;
X2 Y2
---------- ----------
21 21
22 22
x1=2
中有多少行并不重要,您希望将它们全部更新为x2=22
。因此,x1
不必唯一,您也不需要英国/ PK。但是y1
必须是唯一的,因此您知道y2
的哪个单个值用于这些x1=2
行的 all 。
我不明白的是,如果涉及的列被声明为唯一的或正在更新的实际值,则视图是否成为保留键的键。
是列,而不是值。但是我认为我并没有很好地解释一下,因为您正在做set x2=y2
,它可以看到只有tabx
表实际上正在被更新;因此它需要能够确定tabx
表上的哪些行受到了影响,然后需要针对与taby
行匹配的所有 行进行计算从连接条件中获取y2
的值-
对于每个要更新的x2
,它必须标识要使用的单个y2
值,方法是查找taby
所在的行taby.y1
,该行的 tabx.x1
。如果在taby
中有-或可能有-符合该条件的多个行,那么在我的示例中,它将不知道要使用哪个选项– 22或222。 taby
中必须有一个匹配项,因此y1
必须是唯一的,并且必须通过英国或PK 声明为唯一。
可能会有许多不同的x2
值更新为相同的y2
值;你也可以
insert into tabx values(2,13);
insert into tabx values(2,14);
etc.
,所有这些值仍将更新为相同的值-22-因为所有这些行中的非唯一x1
值仍映射到该表UK /的单个ytab
行通过加入条件进行PK。
答案 1 :(得分:1)
如果您不希望使用键(如AlexPoole所建议的那样),则可以轻松地将其转换为MERGE语句(这是我们在每次更新视图时每次遇到“非键保留”错误时都会尝试的操作) :
MERGE
INTO tabx
USING taby
ON (x1 = y1)
WHEN MATCHED THEN
UPDATE
SET x2 = y2
;