2012-02-02 19 views
3

にマージ/更新するために、私のPL/SQLスクリプトで私を助けることができますクエリを改善するための提案は、誰もが、私はそれが正しいかどうか、誰もがいずれかを持っている場合、私は思っていたデータベース</p> <p>に/更新レコードをマージするために、カーソルを作ったデータベース

DECLARE 
CURSOR c_itemloc 
IS 
SELECT 
    item , 
    loc , 
    loc_type , 
    source_method , 
    primary_supp , 
    source_wh 
FROM 
    (SELECT dc_vert.item , 
    dc_vert.loc , 
    dc_vert.loc_type , 
    dc_vert.source_method , 
    dc_vert.primary_supp , 
    w.primary_vwh source_wh --,dc_vert.source_wh 
    , 
    dc_vert.actie , 
    MAX(dc_vert.actie) over (PARTITION BY dc_vert.item, dc_vert.loc) actie_max , 
    COUNT(dc_vert.primary_supp) over (PARTITION BY dc_vert.item, dc_vert.loc) primary_count 
    FROM dc_item_loc_pim_lms dc_vert , 
    item_supplier isu , 
    store sto , 
    wh w 
    WHERE dc_vert.primary_supp IS NOT NULL 
    AND isu.item     = dc_vert.item 
    AND dc_vert.primary_supp  = isu.supplier 
    AND W.WH      = dc_vert.source_wh 
    AND sto.store     = dc_vert.loc 
    AND ISU.SUPP_DISCONTINUE_DATE >= SYSDATE 
) 
    WHERE actie  = actie_max 
    AND primary_count = 1; 
    l_item item_loc.item%TYPE; 
    l_loc item_loc.loc%TYPE; 
    loc_type item_loc.loc_type%TYPE; 
    l_source_method item_loc.source_method%TYPE; 
    l_primary_supp item_loc.primary_supp%TYPE; 
    l_source_wh item_loc.source_wh%TYPE; 

    i  NUMBER; 
    l_commit VARCHAR2(1) := 'Y'; 
    BEGIN 
    i    :=0; 
    FOR r_itemloc IN c_itemloc 
    LOOP 
    i := i+1; 
    UPDATE item_loc il 
    SET 
    il.source_method  = r_itemloc.source_method ,  -- 'S' 
    il.loc_type    = r_itemloc.loc_type ,  -- 'S' 
    il.primary_supp   = r_itemloc.primary_supp , 
    il.source_wh   = r_itemloc.source_wh , 
    il.last_update_datetime = SYSDATE 
    WHERE item     = r_itemloc.item 
    AND loc     = r_itemloc.loc; 
    IF l_commit     = 'Y' AND mod(i, 1000) = 0 THEN 
    COMMIT ; 
    END IF; 
    END LOOP; 
    EXCEPTION 
    WHEN OTHERS THEN 
    dbms_output.put_line('SOMETHING WENT WRONG'); 
    END; 
+0

を使用するためにあなたを示唆していないだろうクエリの実行前に再チェックされます。 – Eve

+0

@を使用して変数を宣言することを個人的にお勧めします。他の人がコードを読み込んだときに読みやすくするが、既存のコードを変更したい場合はあなた次第です。 。私のコード例を無視してください。 – MethodMan

答えて

4

1)意味のあるエラーを無意味なものに置き換えます。さらに、set output onを持っていない場合、エラーは完全には見逃されます。例外ブロックを削除するだけです。できない場合は、少なくともSQLERRM、おそらくDBMS_UTILITY.FORMAT_ERROR_BACKTRACEDBMS_OUTPUTにダンプする必要があります。エラーを捕捉して記録するには、例外の詳細を自律型トランザクションを使用してテーブルに書き込む別のプロシージャに渡す必要があります。その場合でも、記録した後でエラーを再発生させるのが最良です。

2)すべてのXレコードをコミットすることは、ほとんどの場合、貧弱な方法です。これらのレコードがすべて一緒に更新される場合、それらは同じトランザクションの一部である必要があります。

3)UPDATEまたはMERGEのいずれかを使用して、単一のステートメントでこれを実行できます。コンテキストスイッチを追加する必要がないので、一般的にはこれが好ましい。個人的に、私はこのシナリオでMERGEが好き:

MERGE INTO item_loc il 
USING  (SELECT item, 
        loc, 
        loc_type, 
        source_method, 
        primary_supp, 
        source_wh 
      FROM (SELECT dc_vert.item, 
          dc_vert.loc, 
          dc_vert.loc_type, 
          dc_vert.source_method, 
          dc_vert.primary_supp, 
          w.primary_vwh source_wh, 
          dc_vert.actie, 
          MAX(dc_vert.actie) OVER (PARTITION BY dc_vert.item, dc_vert.loc) actie_max, 
          COUNT(dc_vert.primary_supp) OVER (PARTITION BY dc_vert.item, dc_vert.loc) primary_count 
        FROM dc_item_loc_pim_lms dc_vert, 
          item_supplier isu, 
          store sto, 
          wh w 
        WHERE dc_vert.primary_supp IS NOT NULL 
         AND isu.item = dc_vert.item 
         AND dc_vert.primary_supp = isu.supplier 
         AND w.wh = dc_vert.source_wh 
         AND sto.store = dc_vert.loc 
         AND isu.supp_discontinue_date >= SYSDATE) 
      WHERE actie = actie_max AND primary_count = 1) itemloc 
ON   (il.item = itemloc.item AND il.loc = itemloc.loc) 
WHEN MATCHED THEN 
    UPDATE SET 
     il.source_method   = itemloc.source_method, 
     il.loc_type    = itemloc.loc_type, 
     il.primary_supp   = itemloc.primary_supp, 
     il.source_wh    = itemloc.source_wh, 
     il.last_update_datetime = SYSDATE; 
7

例外ハンドラを削除)

1 ...コードは、あなたが望む機能的にないと仮定すると。ロギングや再スローなどの処理をしていない限り、処理できない未知の例外をキャッチするメリットはありません。 dbms_outputを呼び出すだけの例外をキャッチすると、例外をデバッグする必要がある例外の詳細とスタックトレースが隠されるだけでなく、呼び出し元がバッファからの読み取りを行わないと例外が完全に非表示になることがあります。dbms_output

2)ループでコミットすることは、一般的には悪い考えです。最も重要なことは、セッションが途中で消滅した場合はどうなりますか?あとでコードを再起動したときに操作を再開することができない部分的にコミットされた更新があります。以前に更新した行と、ダウンストリームの影響を受ける可能性があるコミット済みの行をすべて再更新する必要があります。そして、ループでコミットすれば、実際の理由でコードが遅くなります。

3)テーブルを更新しようとしているのであれば、最も効率的なアプローチは、カーソルを反復処理するのではなく、すべての行を一度に更新する単一のUPDATE文を記述し、行の更新。他の開発者がカーソルを好む他の理由があるかもしれませんが(例えば他の開発者がコードを理解しやすくするかもしれませんが)、パフォーマンスの観点から、SQLで行うことができればSQLは最も効率的なアプローチになります。

0

私がテストしたときに、私はすべてのエラーを見ていないが、私は必要なのに、私は私を更新する前には近代的な結合構文

FROM 
    dc_item_loc_pim_lms dc_vert 
    INNER JOIN item_supplier isu 
     ON dc_vert.item = isu.item AND 
      dc_vert.primary_supp = isu.supplier 
    INNER JOIN store sto 
     ON dc_vert.loc = sto.store 
    INNER JOIN wh w 
     ON dc_vert.source_wh = w.wh 
WHERE 
    dc_vert.primary_supp IS NOT NULL AND 
    isu.supp_discontinue_date >= SYSDATE 
関連する問題