Uma cláusula de expressão de tabela DML só é útil quando você precisa de colunas de mais de uma tabela. No seu caso, você pode usar uma atualização regular com um
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
);
Se você realmente precisa usar colunas de ambas as tabelas, você tem três opções:
- repita a junção no
SET
e oWHERE
cláusula. Isso é fácil de construir, mas não é o ideal. - Expressão de tabela DML. Isso deve funcionar, se você tiver os índices corretos.
-
MERGE
, abaixo está um exemplo.
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');
Isso não responde diretamente à sua pergunta, mas fornece algumas soluções alternativas. Não consigo reproduzir o erro que você está recebendo. Eu precisaria de um caso de teste completo para analisar melhor.
Aconselhamento genérico para visualizações atualizáveis
Um dos principais problemas das visualizações atualizáveis é o grande número de restrições nas consultas que elas podem conter. A consulta ou visualização não deve conter muitos recursos, como DISTINCT, GROUP BY, certas expressões, etc. Consultas com esses recursos podem gerar a exceção "ORA-01732:operação de manipulação de dados não legal nesta visualização".
A consulta de exibição atualizável deve retornar inequivocamente cada linha da tabela modificada apenas uma vez. A consulta deve ser “preservada por chave”, o que significa que o Oracle deve ser capaz de usar uma chave primária ou restrição exclusiva para garantir que cada linha seja modificada apenas uma vez.
Para demonstrar por que a chave preservada é importante, o código abaixo cria uma instrução de atualização ambígua. Ele cria duas tabelas, a primeira tabela tem uma linha e a segunda tabela tem duas linhas. As tabelas se unem pela coluna
A
, e tente atualizar a coluna B
na primeira tabela. Nesse caso é bom que o Oracle impeça a atualização, caso contrário o valor seria não determinístico. Às vezes, o valor seria definido como "1", às vezes, seria definido como "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;
O
MERGE
declaração não tem as mesmas restrições. O MERGE
A instrução parece tentar detectar ambiguidade em tempo de execução, em vez de tempo de compilação. Infelizmente
MERGE
nem sempre faz um bom trabalho na detecção de ambiguidade. No Oracle 12.2, a instrução abaixo funcionará ocasionalmente e falhará. Fazer pequenas alterações na consulta pode fazê-la funcionar ou falhar, mas não consigo encontrar um padrão específico. --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
falha em tempo de compilação se for teoricamente possível ter duplicatas. Algumas declarações que devem trabalho não será executado. MERGE
falha se o banco de dados detectar linhas instáveis em tempo de execução. Algumas declarações que não devem trabalho ainda será executado.