您的位置:首页 > 其它

ORA-01779: cannot modify a column which maps to a non key-preserved table

2012-08-06 17:27 477 查看
http://ora-01779.ora-code.com/

ORA-01779:

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.

/article/4198741.html

Oracle中试图对一个子查询进行更新时可能会出现ORA-01779错误。该错误的内容为:

ORA-01779: cannot modify a column which maps to a non-key-preserved table

例如,使用以下的更新查询就会出现该错误。

CREATE TABLE test1 ( id integer primary key, num integer );

INSERT INTO test1 VALUES (1,0);

INSERT INTO test1 VALUES (2,0);

INSERT INTO test1 VALUES (3,0);

INSERT INTO test1 VALUES (4,0);

CREATE TABLE test2 ( id integer, num integer, upd integer );

INSERT INTO test2 VALUES (1,10, 0);

INSERT INTO test2 VALUES (2,20, 1);

UPDATE ( SELECT t1.id id1, t1.num num1, t2.id id2, t2.num num2

FROM test1 t1, test2 t2 WHERE t1.id=t2.id AND t2.upd=1 )

SET num1=num2; ORA-01779: cannot modify a column which maps to a non-key-preserved table

这个错误的意思是,子查询的结果中,更新数据源(test2)的内容不唯一,导致被更新对象(test1)中的一行可能对应数据源(test2)中的多行。 本例中,test2表的id不唯一,因此test2表中可能存在id相同但是num不相同的数据,这种数据是无法用来更新 test1 的。

解决方法就是保证数据源的唯一性,例如本例中可以为test2.id创建一个唯一索引:

CREATE UNIQUE INDEX test2_idx_001 ON test2 (id);

之后上面的更新就可以执行了。

另外也可以强制 Oracle 执行,方法是加上 BYPASS_UJVC 注释。

UPDATE

( SELECT /*+ BYPASS_UJVC */ t1.id id1, t1.num num1, t2.id id2, t2.num num2

FROM test1 t1, test2 t2

WHERE t1.id=t2.id AND t2.upd=1 )

SET num1=num2;

BYPASS_UJVC的作用是跳过Oracle的键检查。 这样虽然能够执行了,但是如果test2中存在不唯一的数据,test1就会被更新多次而导致意想不到的结果。

==================

http://www.itpub.net/thread-225291-1-1.html

view的更改是有限制的

General Rule

Any INSERT, UPDATE, or DELETE operation on a join view can modify only one underlying base table at a time.

UPDATE Rule

All updatable columns of a join view must map to columns of a key-preserved table. If the view is defined with the WITH CHECK OPTION clause, then all join columns and all columns of repeated tables are non-updatable.

DELETE Rule

Rows from a join view can be deleted as long as there is exactly one key-preserved table in the join. If the view is defined with the WITH CHECK OPTION clause and the key preserved table is repeated, then the rows cannot be deleted from the view.

INSERT Rule

An INSERT statement must not explicitly or implicitly refer to the columns of a non-key preserved table. If the join view is defined with the WITH CHECK OPTION clause, INSERT statements are not permitted.

1)不可以的。view同一时刻只能对一个表进行操作。

2)“cannot modify a column which maps to a non key-preserved table”意思就是:

当对一个view进行delete、insert、update时,被(涉及到的)view列所映射table列(或列的组合)必须是有主健约束的,目的是要保证在同一时刻只能针对一条记录操作。

3)如果要实现“用一条SQL语句,想通过视图同时往三个表中插入数据”,正如楼上所说的,可以在触发器里代码实现。

=============================

http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:548422757486

You Asked

Could you explain me about  Key-preserved table  concept
in join views.i know that a table is ket preserved if every key of the table can also be
a key of result of the join.
but i not understand meaning of this.

Thanks


and we said...

Key preserved means the row from the base table will appear AT MOST ONCE in the output
view on that table.

For example, lets say I have tables T1 and T2 and a view:

create view T
as
select * from t1, t2 where t1.x = t2.y
/

Now, I do not know if for any given row in T1 if it will appear in the output result set
0, 1 or MANY times (eg: if a given t1.x is joined to every row in t2 by y and there are 2
rows in t2 with the same value for y -- then that row in t1 will be output 2 times).

For example, say you have:

T1.X                      T2.Y
------                    --------
1                         1
1

That single row T1 in the view will be output 2 times.  If we were to issue:

update T set x = x+1;

The outcome would be to set X=3, since it appears in there 2 times.  That is not key
preserved and we will not allow that to happen (the results can be ambigous depending on
an access plan -- the same statements could result in DIFFERENT data in the database
depending on how we access the data).

So, if you can assert that a given row in a table will appear at most once in the view --
that table is "key preserved" in the view.  It sounds backwards because in our example
above -- its T2 that needs a unique constraint on Y if we want T1 to be key preserved
(you put the key on T2, not on T1 to key preserve T1!)

http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:273215737113

You Asked

Tom,

When updating a column with an update-statement, the value of some records (records that
don't need to be updated), are changed into the value NULL. I use the next statement:
update    table    name B
set        columnname    =
(    select    value
from    lookup    O
where    B.keyname = O.keyname
and    O.Othercolumn = Other_value);

As a result all the necessary changes are made, but also the records that don't need to
be updated: they get the Null-value. Is there a way of avoiding this, because we do need
to update the records frequently, but not all records at the same time.
Is there a kind of workaround we can use for updating the records that need to be updated
without changing the other records too with a Null value?

Thanks and greetings,

David Boot


and we said...

There are at least 2 ways to perform this sort of co-related update correctly.  I'll show
my preferred method (update a join) and then another method that'll work if you cannot
put a unique constraint on LOOKUP(keyname) (which is needed for the join update).

Here are the test tables:

scott@ORA734.WORLD> create table name
2  ( keyname int,
3    columnName varchar2(25)
4  )
5  /
Table created.

scott@ORA734.WORLD> create table lookup
2  ( keyname int PRIMARY KEY,
3    value varchar2(25),
4    otherColumn int
5  )
6  /
Table created.

scott@ORA734.WORLD> insert into name values ( 100, 'Original Data' );
1 row created.

scott@ORA734.WORLD> insert into name values ( 200, 'Original Data' );
1 row created.

scott@ORA734.WORLD> insert into lookup values ( 100, 'New Data', 1 );
1 row created.

scott@ORA734.WORLD> commit;
Commit complete.

here is the "other_value" parameter you are using in the above update you
attempted...

scott@ORA734.WORLD> variable other_value number
scott@ORA734.WORLD> exec :other_value := 1
PL/SQL procedure successfully completed.

scott@ORA734.WORLD> select * from name;

KEYNAME COLUMNNAME
---------- -------------------------
100 Original Data
200 Original Data

Here we update a join.  We can only modify the columns in one of the tables and the
other tables we are *NOT* modifying must be "key preserved" -- that is, we must be able
to verify that at most one record will be returned when we join NAME to this other table.
In order to do that, keyname in LOOKUP must either be a primary key or have a unique
constraint applied to it...

scott@ORA734.WORLD> update
2    ( select columnName, value
3        from name, lookup
4       where name.keyname = lookup.keyname
5         and lookup.otherColumn = :other_value )
6     set columnName = value
7  /

1 row updated.

scott@ORA734.WORLD> select * from name;

KEYNAME COLUMNNAME
---------- -------------------------
100 New Data
200 Original Data

See, the other data is untouched and only the rows we wanted are updated..

scott@ORA734.WORLD> rollback;
Rollback complete.

scott@ORA734.WORLD> select * from name;

KEYNAME COLUMNNAME
---------- -------------------------
100 Original Data
200 Original Data

Now, this way will work with no constraints on anything -- you do not need the primary
key/unique constraint on lookup (but you better be sure the subquery returns 0 or 1
records!).

It is very much like your update, just has a where clause so that only rows that we find
matches for are actually updated...

scott@ORA734.WORLD> update name
2     set columnName = ( select value
3                          from lookup
4                         where lookup.keyname = name.keyname
5                           and otherColumn = :other_value )
6   where exists ( select value
7                    from lookup
8                   where lookup.keyname = name.keyname
9                     and otherColumn = :other_value )
10  /

1 row updated.

scott@ORA734.WORLD> select * from name;

KEYNAME COLUMNNAME
---------- -------------------------
100 New Data
200 Original Data
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐