sql >> データベース >  >> RDS >> Oracle

Oracleでの結合を使用した更新ステートメントの何が問題になっていますか?

    良い質問です。

    あなたの状況をシミュレートするために、私はサンプルテーブルを作成しました:

    SQL> create table t_debtor(id_debtor,header)
      2  as
      3  select 1, 'Header 1' from dual union all
      4  select 2, null from dual union all
      5  select 3, 'Header 3' from dual
      6  /
    
    Tabel is aangemaakt.
    
    SQL> create table t_element (id_element,id_debtor,insurer)
      2  as
      3  select 1, 1, 'to be updated' from dual union all
      4  select 2, 1, 'to be updated' from dual union all
      5  select 3, 2, 'not to be updated' from dual union all
      6  select 4, 2, 'not to be updated' from dual union all
      7  select 5, 3, 'to be updated' from dual
      8  /
    
    Tabel is aangemaakt.
    

    そして、現在の更新ステートメントで、問題が明らかになります。「更新されない」値はNULLに設定されます:

    SQL> update
      2      T_ELEMENT elt
      3      set elt.INSURER = (
      4          select HEADER
      5              from T_DEBTOR debtor
      6              where
      7                  debtor.HEADER is not null
      8                  and debtor.ID_DEBTOR = elt.ID_DEBTOR)
      9  /
    
    5 rijen zijn bijgewerkt.
    
    SQL> select * from t_element
      2  /
    
    ID_ELEMENT  ID_DEBTOR INSURER
    ---------- ---------- -----------------
             1          1 Header 1
             2          1 Header 1
             3          2
             4          2
             5          3 Header 3
    
    5 rijen zijn geselecteerd.
    

    この更新を行う最良の方法は、両方のテーブルの結合を更新することです。ただし、いくつかの制限があります:

    SQL> rollback
      2  /
    
    Rollback is voltooid.
    
    SQL> update ( select elt.insurer
      2                , dtr.header
      3             from t_element elt
      4                , t_debtor dtr
      5            where elt.id_debtor = dtr.id_debtor
      6              and dtr.header is not null
      7         )
      8     set insurer = header
      9  /
       set insurer = header
           *
    FOUT in regel 8:
    .ORA-01779: cannot modify a column which maps to a non key-preserved table
    

    バイパスujvcヒントを使用すると、この制限を回避できますが、t_debtor.id_debtorが一意であることが本当に確実でない限り、回避することはお勧めできません。

    SQL> update /*+ bypass_ujvc */
      2         ( select elt.insurer
      3                , dtr.header
      4             from t_element elt
      5                , t_debtor dtr
      6            where elt.id_debtor = dtr.id_debtor
      7              and dtr.header is not null
      8         )
      9     set insurer = header
     10  /
    
    3 rijen zijn bijgewerkt.
    
    SQL> select * from t_element
      2  /
    
    ID_ELEMENT  ID_DEBTOR INSURER
    ---------- ---------- -----------------
             1          1 Header 1
             2          1 Header 1
             3          2 not to be updated
             4          2 not to be updated
             5          3 Header 3
    
    5 rijen zijn geselecteerd.
    

    主キーを追加することをお勧めします。おそらくこれはすでに配置されているでしょう:

    SQL> rollback
      2  /
    
    Rollback is voltooid.
    
    SQL> alter table t_debtor add primary key (id_debtor)
      2  /
    
    Tabel is gewijzigd.
    
    SQL> update ( select elt.insurer
      2                , dtr.header
      3             from t_element elt
      4                , t_debtor dtr
      5            where elt.id_debtor = dtr.id_debtor
      6              and dtr.header is not null
      7         )
      8     set insurer = header
      9  /
    
    3 rijen zijn bijgewerkt.
    
    SQL> select * from t_element
      2  /
    
    ID_ELEMENT  ID_DEBTOR INSURER
    ---------- ---------- -----------------
             1          1 Header 1
             2          1 Header 1
             3          2 not to be updated
             4          2 not to be updated
             5          3 Header 3
    
    5 rijen zijn geselecteerd.
    

    よろしく、ロブ。



    1. T-SQLを使用してRPC出力を有効にする方法

    2. PHPとMySQLを使用したUnicode文字列(हिन्दी)の保存と表示

    3. LONGデータ型Oracleの不正使用

    4. レルムからSqliteに移行することは可能ですか?