Oracle
 sql >> Baza danych >  >> RDS >> Oracle

ORA-01779:nie można modyfikować kolumny, która mapuje do tabeli niezachowanej kluczem

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:

  1. powtórz sprzężenie w SET i WHERE klauzula. Jest to łatwe do zbudowania, ale nie optymalne.
  2. Wyrażenie tabeli DML. To powinno działa, jeśli masz prawidłowe indeksy.
  3. 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ć.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Kto wymyślił termin węzeł DIANA i jak obliczył, że 6 000 000 LOC to około 67108864 (2**26) węzłów DIANA?

  2. Unikaj wstawiania wartości wykładniczej w kolumnie DB Float

  3. potrzebujesz pomocy w optymalizacji zapytania Oracle

  4. ORA-22813:wartość operandu przekracza limity systemowe

  5. Dowiedz się więcej o pakiecie DBMS_OUTPUT w Oracle