我有这个程序:
create or replace procedure changePermissionsToRead( datasource in varchar2 ) IS begin update ( select * from WEB_USERROLE ur , WEB_USERDATASOURCE ds where ur.username = ds.username and ds.datasource = datasource and ur.READ_ONLY <> 'Y' ) r set r.role = replace(r.role, 'FULL', 'READ'); end;
我收到以下错误:
ORA-01779
但是如果我取出更新,然后写:
update ( select * from WEB_USERROLE ur , WEB_USERDATASOURCE ds where ur.username = ds.username and ds.datasource = 'PIPPO' and ur.READ_ONLY <> 'Y' ) r set r.role = replace(r.role, 'FULL', 'READ');
那么这很好。你能告诉我发生了什么吗?
仅当您需要多个表中的列时,DML表表达式子句才有用。在您的情况下,您可以使用带有的常规更新EXISTS:
EXISTS
update web_userrole set role = replace(role, 'FULL', 'READ') where read_only <> 'Y' and exists ( select 1/0 from web_userdatasource where datasource = p_datasource and username = web_userrole.username );
如果确实需要使用两个表中的列,则可以使用以下三个选项:
SET
WHERE
MERGE
merge into web_userrole
using ( select distinct username from web_userdatasource where datasource = p_datasource ) web_userdatasource on ( web_userrole.username = web_userdatasource.username and web_userrole.read_only <> ‘Y’ ) when matched then update set role = replace(role, ‘FULL’, ‘READ’);
这不会直接回答您的问题,而是提供了一些解决方法。我无法重现您遇到的错误。我需要一个完整的测试用例来进一步研究它。
可更新视图的主要问题之一是对它们所包含查询的大量限制。查询或视图不得包含很多功能,例如DISTINCT,GROUP BY,某些表达式等。使用这些功能的查询可能会引发异常“ ORA-01732:对该视图不合法的数据操作”。
可更新视图查询必须仅一次明确地返回修改后的表的每一行。该查询必须“保留”,这意味着Oracle必须能够使用主键或唯一约束来确保每行仅被修改一次。
为了说明为什么保留键很重要,下面的代码创建了一个模糊的update语句。它创建两个表,第一个表具有一行,第二个表具有两行。这些表按列连接A,并尝试更新B第一个表中的列。在这种情况下,Oracle最好阻止更新,否则该值将是不确定的。有时该值将设置为“ 1”,有时将其设置为“ 2”。
A
B
--Create table to update, with one row. create table test1 as select 1 a, 1 b from dual; --Create table to join two, with two rows that match the other table's one row. create table test2 as select 1 a, 1 b from dual union all select 1 a, 2 b from dual; --Simple view that joins the two tables. create or replace view test_view as select test1.a, test1.b b_1, test2.b b_2 from test1 join test2 on test1.a = test2.a; --Note how there's one value of B_1, but two values for B_2. select * from test_view; A B_1 B_2 - --- --- 1 1 1 1 1 2 --If we try to update the view it fails with this error: --ORA-01779: cannot modify a column which maps to a non key-preserved table update test_view set b_1 = b_2; --Using a subquery also fails with the same error. update ( select test1.a, test1.b b_1, test2.b b_2 from test1 join test2 on test1.a = test2.a ) set b_1 = b_2;
该MERGE语句没有相同的限制。该MERGE语句似乎试图在运行时而不是编译时检测歧义。
不幸的是MERGE,并非总是能很好地发现歧义。在Oracle 12.2上,以下语句有时会起作用,然后失败。对查询进行小的更改可能会使它工作或失败,但是我找不到特定的模式。
--The equivalent MERGE may work and changes "2" rows, even though there's only one. --But if you re-run, or uncomment out the "order by 2 desc" it might raise: -- ORA-30926: unable to get a stable set of rows in the source tables merge into test1 using ( select test1.a, test1.b b_1, test2.b b_2 from test1 join test2 on test1.a = test2.a --order by 2 desc ) new_rows on (test1.a = new_rows.a) when matched then update set test1.b = new_rows.b_2;
UPDATE如果理论上可能有重复,则在编译时失败。某些 应该 起作用的语句将不会运行。
UPDATE
MERGE如果数据库在运行时检测到不稳定的行,则失败。有些语句 不应该 工作将仍然运行。