我正在尝试使用以下代码更新同一查询中2个不同表中的数据:
UPDATE (SELECT s.passNumb, a.hour, a.minute, p.number, s.situation
FROM passwords s
JOIN atend a ON s.passNumb = a.passNumb
JOIN points p ON a.number = p.number
WHERE s.passNumb = 1 AND
p.number = 1)
SET a.hour = TO_CHAR(SYSDATE, 'HH24'),
a.minute = TO_CHAR(SYSDATE, 'MI'),
s.situation = 'F';
但是我收到了这个错误:Cannot modify a column which maps to a non key-preserved table
。我做错了什么?
答案 0 :(得分:1)
带有连接的视图(或包含连接的内联视图)必须满足以下条件才能更新:
https://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_8004.htm
如果您希望连接视图可更新,则以下所有内容 条件必须为真:
DML语句必须只影响联接的一个表。
对于INSERT语句,不能使用CHECK创建视图 OPTION以及插入值的所有列必须来自 一张钥匙保存的桌子。保存密钥的表是每个表 基表中的主键或唯一键值也是唯一的 加入视图。
对于UPDATE 语句,不得使用WITH CHECK创建视图 OPTION和更新的所有列必须从密钥保留中提取 表强>
第一个条件相当明显:The DML statement must affect only one table underlying the join.
但它是什么意思:“密钥保留表”?
密钥保留表是每个主键或唯一的表 基表中的键值在连接视图中也是唯一的。
密钥保留表意味着此表格中的每一行在视图结果中最多显示 。
考虑一个简单的例子:
CREATE TABLE users(
user_id int primary key,
user_name varchar(100),
age int
);
insert into users values(1,'Tom', 22);
CREATE TABLE emails(
user_id int,
email varchar(100)
);
Insert into emails values( 1, 'tom@somedomain.com' );
Insert into emails values( 1, 'tom@www.example.org' );
commit;
加入:
SELECT *
FROM users u
JOIN emails e ON u.user_id = e.user_id;
USER_ID USER_NAME AGE USER_ID EMAIL
---------- --------------- ---------- ---------- --------------------
1 Tom 22 1 tom@somedomain.com
1 Tom 22 1 tom@www.example.org
如果查看此联接的结果,很明显:
现在:此更新是可以接受的,因为它更新了此连接中的密钥保留列(表):
UPDATE (
SELECT * FROM users u
JOIN emails e ON u.user_id = e.user_id
)
SET email = email || '.it' ;
USER_ID USER_NAME AGE USER_ID EMAIL
---------- --------------- ---------- ---------- -------------------------
1 Tom 22 1 tom@somedomain.com.it
1 Tom 22 1 tom@www.example.org.it
但是这个更新无法完成,因为它触及非密钥保留表中的列:
UPDATE (
SELECT * FROM users u
JOIN emails e ON u.user_id = e.user_id
)
SET age = age + 2;
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.
如果你想一会儿......汤姆在联接的结果中出现2次(但users
表中只有一个汤姆)。
当我们尝试在此联接中更新age = age + 2
时,此更新的结果应该是什么?
Tom应该只更新一次吗?
这次更新后Tom应该是22 + 2 = 24岁吗?
或者汤姆应该更新两次(因为它在连接结果中出现两次)所以它应该是22 + 2 + 2 = 26岁。
另一个例子 - 请告诉我这次更新应该是什么结果?:
UPDATE ( ....our join ... ) SET age = length( email );
有很难的问题:)
因此,Oracle阻止更新非密钥保留表。
错误消息提供此提示:
*Action: Modify the underlying base tables directly.
这意味着我们必须使用单独的UPDATE命令直接更新此表:
UPDATE users SET age = age + 2