非键保留的表错误,用于更新唯一数据

时间:2018-07-03 10:07:26

标签: sql oracle sql-view

我对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

2 个答案:

答案 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
;