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
);
両方のテーブルの列を本当に使用する必要がある場合は、次の3つのオプションがあります。
-
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');
これはあなたの質問に直接答えることはありませんが、代わりにいくつかの回避策を提供します。発生したエラーを再現できません。さらに詳しく調べるには、完全なテストケースが必要です。
更新可能なビューに関する一般的なアドバイス
更新可能なビューの主な問題の1つは、ビューに含めることができるクエリに対する多数の制限です。クエリまたはビューには、DISTINCT、GROUP BY、特定の式などの多くの機能を含めることはできません。これらの機能を使用したクエリでは、「ORA-01732:このビューではデータ操作操作が無効です」という例外が発生する場合があります。
>更新可能なビュークエリは、変更されたテーブルの各行を1回だけ明確に返す必要があります。クエリは「キー保存」する必要があります。つまり、Oracleは主キーまたは一意性制約を使用して、各行が1回だけ変更されるようにする必要があります。
キーの保持が重要である理由を示すために、以下のコードはあいまいな更新ステートメントを作成します。 2つのテーブルが作成され、最初のテーブルには1つの行があり、2番目のテーブルには2つの行があります。テーブルは列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
データベースが実行時に不安定な行を検出すると失敗します。 すべきではないいくつかのステートメント 作業は引き続き実行されます。