我有这个程序:
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;
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
ORA-01779
Run Code Online (Sandbox Code Playgroud)
但如果我拿出更新,我写道:
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');
Run Code Online (Sandbox Code Playgroud)
然后这很好用.你能告诉我发生了什么吗?
Jon*_*ler 12
只有在需要来自多个表的列时,DML表表达式子句才有用.在您的情况下,您可以使用常规更新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
);
Run Code Online (Sandbox Code Playgroud)
如果您确实需要使用两个表中的列,则有三个选项:
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');
Run Code Online (Sandbox Code Playgroud)这不能直接回答您的问题,而是提供一些解决方法.我无法重现你得到的错误.我需要一个完整的测试用例来进一步研究它.
可更新视图的主要问题之一是对它们可以包含的查询的大量限制.查询或视图不得包含许多功能,例如DISTINCT,GROUP BY,某些表达式等.具有这些功能的查询可能会引发异常"ORA-01732:数据操作操作在此视图中不合法".
可更新视图查询必须只明确地返回修改后的表的每一行.查询必须是"密钥保留",这意味着Oracle必须能够使用主键或唯一约束来确保每行只修改一次.
为了说明为什么密钥保留很重要,下面的代码会创建一个不明确的更新语句.它创建了两个表,第一个表有一行,第二个表有两行.表按列连接A,并尝试更新B第一个表中的列.在这种情况下,Oracle阻止更新是好的,否则该值将是非确定性的.有时将值设置为"1",有时将其设置为"2".
--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;
Run Code Online (Sandbox Code Playgroud)
该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;
Run Code Online (Sandbox Code Playgroud)
UPDATE如果在理论上可能有重复,则在编译时失败.一些应该运行的语句将无法运行.
MERGE如果数据库在运行时检测到不稳定的行,则会失败 一些不应该工作的陈述仍然会运行.
| 归档时间: |
|
| 查看次数: |
58053 次 |
| 最近记录: |