Oracle
 sql >> база данни >  >> RDS >> Oracle

ORA-01779:не може да модифицира колона, която съответства на таблица без запазен ключ

Клаузата за израз на 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
    );

Ако наистина трябва да използвате колони от двете таблици, имате три възможности:

  1. повторете присъединяването в SET и WHERE клауза. Това е лесно за изграждане, но не е оптимално.
  2. Израз на DML таблица. Това трябва работа, ако имате правилните индекси.
  3. 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 се проваля, ако базата данни открие нестабилни редове по време на изпълнение. Някои твърдения, които не трябва работата ще продължи.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Съхранена процедура на Oracle, връщаща референтен курсор срещу асоциативни масиви

  2. Oracle (ORA-02270) :няма съвпадащ уникален или първичен ключ за тази грешка в списъка с колони

  3. Вземане на запис с максимална дата

  4. Oracle PL/SQL версия 12.2.0.1.0 срещу 12.1.0.2.0 - незабавно изпълнение с параметри

  5. Pivot/Crosstab Query в Oracle 10g (Динамичен номер на колона)