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
        );
    

    両方のテーブルの列を本当に使用する必要がある場合は、次の3つのオプションがあります。

    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');
      

    これはあなたの質問に直接答えることはありませんが、代わりにいくつかの回避策を提供します。発生したエラーを再現できません。さらに詳しく調べるには、完全なテストケースが必要です。

    更新可能なビューに関する一般的なアドバイス

    更新可能なビューの主な問題の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 データベースが実行時に不安定な行を検出すると失敗します。 すべきではないいくつかのステートメント 作業は引き続き実行されます。




    1. cpanelでウェブサイトフォルダにログインする際のphp警告

    2. 大文字と小文字を区別するRLIKE

    3. MySQLで日付で注文する方法

    4. 日付と時刻をMysqlに挿入します