Клаузата за израз на 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
);
Ако наистина трябва да използвате колони от двете таблици, имате три възможности:
- повторете присъединяването в
SET
иWHERE
клауза. Това е лесно за изграждане, но не е оптимално. - Израз на DML таблица. Това трябва работа, ако имате правилните индекси.
-
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 трябва да може да използва първичен ключ или уникално ограничение, за да гарантира, че всеки ред се променя само веднъж.
За да демонстрира защо запазването на ключ е важно, кодът по-долу създава двусмислен израз за актуализиране. Той създава две таблици, първата таблица има един ред, а втората има два реда. Таблиците се обединяват чрез колона 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;
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
се проваля по време на компилиране, ако теоретично е възможно да има дубликати. Някои твърдения, които трябва работата няма да работи.
MERGE
се проваля, ако базата данни открие нестабилни редове по време на изпълнение. Някои твърдения, които не трябва работата ще продължи.