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

別のテーブルに結合された1つのテーブルからのレコードの削除SQL

    OUTER JOINを使用する必要はありません 応答する行数のチェックを除いて。 しない 削除されます。

    このようなクエリの例を以下に示します(回答の最後に提供されている生成されたテストデータを使用します)

    with del as (
    select delta.id, delta.version,
    decode(big.id,null,0,1) is_deleted
    from delta
    left outer join big 
    on delta.id = big.id and delta.version = big.version
    )
    select is_deleted, count(*) cnt, max(id||'.'||version) eg_id_vers
    from del
    group by is_deleted;
    
    IS_DELETED        CNT  EG_ID_VERS                                                                   
    ---------- ---------- ----------
             1      20000 99995.0   
             0         20 100100.0   
    

    データサイズでは、HASH JOINを使用する必要があります full table scanを使用 許容できるパフォーマンスを得るために両方のテーブルで。

    DELETEの実行方法には基本的に2つのオプションがあります

    更新可能な参加ビュー

    この場合、小さなテーブルには一意のインデックスが必要ですID, VERSION (または主キー)

    create unique index delta_idx on delta(id,version);
    

    反対に、BIGテーブルにはそのような制約があってはなりません 。これは重要です。これは、BIGテーブルが唯一のキー保存テーブルであることを明確に示しているためです。 結合ビューで。

    単純に小さなテーブルに結合を配置します行を複製できません 独自の制約による大きなテーブルから

    こちら 結合ビューの更新の詳細

    delete from 
    (
    select delta.id, delta.version, big.id big_id, big.version
    from big 
    join delta 
    on delta.id = big.id and delta.version = big.version
    )
    

    delete 上記はBIGから行を削除します これが唯一のキー保存テーブルであるため、テーブル (上記の説明を参照)

    このDMLはHASH JOINにつながります

    EXISTSで削除

    小さなテーブルに主キーがない場合(つまり、同じID and VERSIONを持つ重複した行が含まれている可能性がある場合 )フォールバックする必要があります その他の回答 で提案されたソリューションへ 。

    DELETE FROM big 
        WHERE EXISTS (SELECT null
                      FROM delta
                      WHERE delta.id = big.id and delta.version = big.version
                     ) 
    

    インデックスは必要ありません。HASH JOIN RIGHT SEMIを使用した実行プランを期待する必要があります。 、つまり、両方のアプローチに実際の違いはありません。

    テスト用のサンプルデータ

    create table big as
    select 
    trunc(rownum/10) id, mod(rownum,10) version,
    lpad('x',10,'Y') pad
    from dual connect by level <= 1000000;
    
    /* the DELTA table has 50 times less rows,
    allow some rows out of range of the BIG table - those rows will not be deleted **/
    drop table delta;
    create table delta as
    select 
    trunc(rownum*50/10) id, mod(rownum*50,10) version
    from dual connect by level <= 1001000/50;
    
    create unique index delta_idx on delta(id,version);
    


    1. MySQLでの2つのSelectクエリの結果を減算します

    2. Oracle SQL WHERE句で(+)記号はどういう意味ですか?

    3. テーブルに列を追加してから、トランザクション内で更新します

    4. SQLのwhere条件を含むCaseステートメント