sql >> Databáze >  >> RDS >> Oracle

ORA-01779:nelze upravit sloupec, který se mapuje na tabulku bez klíčů

Klauzule výrazu tabulky DML je užitečná pouze v případě, že potřebujete sloupce z více než jedné tabulky. Ve vašem případě můžete použít běžnou aktualizaci s 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
    );

Pokud opravdu potřebujete použít sloupce z obou tabulek, máte tři možnosti:

  1. opakujte spojení v SET a WHERE doložka. To je snadné sestavit, ale není to optimální.
  2. Výraz tabulky DML. Toto by mělo práce, pokud máte správné indexy.
  3. MERGE , níže je příklad.

    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 přímo neodpovídá na vaši otázku, ale poskytuje některá řešení. Nemohu reprodukovat chybu, kterou dostáváte. Potřeboval bych úplný testovací případ, abych se tím mohl dále zabývat.

Obecné rady pro aktualizovatelná zobrazení

Jedním z hlavních problémů s aktualizovatelnými pohledy je velký počet omezení na dotazy, které mohou obsahovat. Dotaz nebo pohled nesmí obsahovat mnoho funkcí, jako je DISTINCT, GROUP BY, určité výrazy atd. Dotazy s těmito funkcemi mohou způsobit výjimku „ORA-01732:operace manipulace s daty není v tomto pohledu legální“.

Aktualizovatelný pohledový dotaz musí jednoznačně vrátit každý řádek upravené tabulky pouze jednou. Dotaz musí být „zachovaný klíč“, což znamená, že Oracle musí být schopen použít primární klíč nebo jedinečné omezení, aby bylo zajištěno, že každý řádek bude upraven pouze jednou.

Abychom demonstrovali, proč je zachování klíče důležité, níže uvedený kód vytvoří nejednoznačné prohlášení o aktualizaci. Vytváří dvě tabulky, první tabulka má jeden řádek a druhá tabulka má dva řádky. Tabulky jsou spojeny sloupcem A a zkuste aktualizovat sloupec B v první tabulce. V tomto případě je dobré, že Oracle aktualizaci brání, jinak by byla hodnota nedeterministická. Někdy by byla hodnota nastavena na "1", někdy byla nastavena 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 prohlášení nemá stejná omezení. MERGE Zdá se, že se příkaz pokouší detekovat nejednoznačnost v době běhu, nikoli v době kompilace.

Bohužel MERGE ne vždy odvádí dobrou práci při odhalování nejednoznačnosti. Na Oracle 12.2 bude níže uvedené prohlášení občas fungovat a pak selže. Provedení malých změn v dotazu může způsobit, že bude fungovat nebo selhat, ale nemohu najít konkrétní vzor.

--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 selže v době kompilace, pokud je teoreticky možné mít duplikáty. Některá tvrzení, která by měla práce se nespustí.

MERGE selže, pokud databáze za běhu zjistí nestabilní řádky. Některá tvrzení, která by neměla práce stále poběží.




  1. Pomocí Moodle vytvořte uživatele a zapište je do kurzů přes SQL

  2. Jak získám datum příštího měsíce z dnešního data a vložím je do své databáze?

  3. Escape řetězec v SQL Server, takže je bezpečné použít ve výrazu LIKE

  4. Zastavte nebo ukončete dlouho běžící dotaz v JDBC