Klauzula wyrażenia tabeli DML jest przydatna tylko wtedy, gdy potrzebne są kolumny z więcej niż jednej tabeli. W Twoim przypadku możesz użyć regularnej aktualizacji z 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
);
Jeśli naprawdę potrzebujesz użyć kolumn z obu tabel, masz trzy opcje:
- powtórz sprzężenie w
SET
iWHERE
klauzula. Jest to łatwe do zbudowania, ale nie optymalne. - Wyrażenie tabeli DML. To powinno działa, jeśli masz prawidłowe indeksy.
-
MERGE
, poniżej znajduje się przykład.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');
To nie odpowiada bezpośrednio na twoje pytanie, ale zamiast tego zapewnia pewne obejścia. Nie mogę odtworzyć wyświetlanego błędu. Potrzebuję pełnego przypadku testowego, aby dokładniej się temu przyjrzeć.
Ogólne porady dotyczące aktualizowanych widoków
Jednym z głównych problemów z aktualizowalnymi widokami jest duża liczba ograniczeń dotyczących zapytań, które mogą zawierać. Zapytanie lub widok nie może zawierać wielu funkcji, takich jak DISTINCT, GROUP BY, niektóre wyrażenia itp. Zapytania z tymi funkcjami mogą wywołać wyjątek „ORA-01732:operacja manipulacji danymi niedozwolona w tym widoku”.
Kwerenda widoku z możliwością aktualizacji musi jednoznacznie zwrócić każdy wiersz zmodyfikowanej tabeli tylko raz. Zapytanie musi być „zachowane kluczem”, co oznacza, że Oracle musi mieć możliwość użycia klucza podstawowego lub ograniczenia unikalności, aby zapewnić, że każdy wiersz zostanie zmodyfikowany tylko raz.
Aby zademonstrować, dlaczego zachowanie klucza jest ważne, poniższy kod tworzy niejednoznaczną instrukcję aktualizacji. Tworzy dwie tabele, pierwsza tabela ma jeden wiersz, a druga tabela ma dwa wiersze. Tabele łączą się kolumną A
i spróbuj zaktualizować kolumnę B
w pierwszej tabeli. W tym przypadku dobrze, że Oracle uniemożliwia aktualizację, w przeciwnym razie wartość byłaby niedeterministyczna. Czasami wartość byłaby ustawiona na „1”, czasami na „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
oświadczenie nie ma takich samych ograniczeń. MERGE
instrukcja wydaje się próbować wykryć niejednoznaczność w czasie wykonywania, zamiast w czasie kompilacji.
Niestety MERGE
nie zawsze dobrze wykrywa niejednoznaczność. W Oracle 12.2 poniższa instrukcja czasami będzie działać, a następnie zawiedzie. Wprowadzenie niewielkich zmian w zapytaniu może sprawić, że będzie ono działać lub zakończyć się niepowodzeniem, ale nie mogę znaleźć konkretnego wzorca.
--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
kończy się niepowodzeniem w czasie kompilacji, jeśli teoretycznie możliwe jest posiadanie duplikatów. Niektóre stwierdzenia, które powinny praca nie działa.
MERGE
kończy się niepowodzeniem, jeśli baza danych wykryje niestabilne wiersze w czasie wykonywania. Niektóre stwierdzenia, które nie powinny praca będzie nadal działać.