[PL/SQL]複数パターンで更新内容を分ける

SQL

複数パターンで更新内容を分ける

例)

前提として実施日は 2020/07/15 とします。

更新パターン1

HOGE_DATE が過去の日付の場合、hoge_cd を「CD98」にする

更新パターン2

HOGE_DATE が当日含む未来の日付の場合、hoge_cd を「CD99」、hoge_date を null にする。

なお、1万レコード単位で更新・コミットするようにしています。

SET SERVEROUTPUT ON;

DECLARE
-- HOGEDATEで更新内容を変えるので取得しておく
CURSOR c_hoge_table IS SELECT id c_id, hoge_date c_hoge_date FROM HOGE_TABLE;
TYPE v_table_type IS TABLE OF c_hoge_table%ROWTYPE INDEX BY BINARY_INTEGER;
TYPE v_update_table_type IS TABLE OF HOGE_TABLE%ROWTYPE;
v_table v_table_type;
-- 更新パターン1に該当するレコード格納用
v_update_table1 v_update_table_type;
-- 更新パターン2に該当するレコード格納用
v_update_table2 v_update_table_type;
v_update_count NUMBER(10) := 0;

BEGIN
 DBMS_OUTPUT.PUT_LINE(TO_CHAR(SYSDATE, 'YYYY/MM/DD HH24:MI:SS') || '[START] UPDATE SQL');
 v_update_table1.delete;
 v_update_table2.delete;

OPEN c_hoge_table;
 LOOP
  --1万レコード単位で更新・コミットする
  FETCH c_hoge_table BULK COLLECT INTO v_table LIMIT 10000;
  EXIT WHEN v_table.count = 0;
  v_update_table1.delete;
  v_update_table2.delete;

  FOR i in 1..v_table.count LOOP
   -- 更新1
   -- HOGE_DATE が過去の日付
   IF(v_table(i).c_hoge_date < '20200715') THEN
    v_update_table1.extend;
    v_update_table1(v_update_table1.count).hoge_cd := 'CD98';
    v_update_table1(v_update_table1.count).id := v_table(i).c_id;

    -- 更新2
    -- HOGE_DATE が当日含む未来の日付
   ELSE
    v_update_table2.extend;
    v_update_table2(v_update_table2.count).hoge_cd := 'CD99';
    v_update_table2(v_update_table2.count).id := v_table(i).c_id;
   END IF;
  END LOOP;

  -- 更新1の実行
  FORALL i IN 1..v_update_table1.count
   UPDATE HOGE_TABLE
   SET
    hoge_cd = v_update_table(i).hoge_cd
   WHERE
    id = v_update_table(i).id;
   v_update_count := v_update_count + SQL%ROWCOUNT;

  -- 更新2の実行
  FORALL i IN 1..v_update_table2.count
   UPDATE HOGE_TABLE
   SET
    hoge_cd = v_update_table2(i).hoge_cd
    ,hoge_date = null
   WHERE
    id = v_update_table2(i).id;
   v_update_count := v_update_count + SQL%ROWCOUNT;

  COMMIT;
 END LOOP;
CLOSE c_hoge_table;

DBMS_OUTPUT.PUTLINE(TO_CHAR(SYSDATE, 'YYYY/MM/DD HH24:MI:SS') || '[END] TOTAL UPDATE:' || v_update_count || 'record');
DBMS_OUTPUT.PUTLINE(TO_CHAR(SYSDATE, 'YYYY/MM/DD HH24:MI:SS') || '[END] UPDATE SQL');

EXCEPTION
 WHEN OTHERS THEN
  DBMS_OUTPUT.PUTLINE(TO_CHAR(SYSDATE, 'YYYY/MM/DD HH24:MI:SS') || '[ERROR] ERRORCODE:' || SQLCODE);
  DBMS_OUTPUT.PUTLINE(TO_CHAR(SYSDATE, 'YYYY/MM/DD HH24:MI:SS') || '[ERROR] ERRORMSG:' || SQLERRM);
  DBMS_OUTPUT.PUTLINE(TO_CHAR(SYSDATE, 'YYYY/MM/DD HH24:MI:SS') || '[END] TOTAL UPDATE:' || v_update_count || 'record');
  -- カーソルが開いていた場合クローズする
  IF c_hoge_table%ISOPEN THEN
   CLOSE c_hoge_table;
  END IF;
  ROLLBACK;
  -- エラー発生を明示的に返却する
  RAISE;
 END;
/

更新数のカウントがおかしい・・

レコードは正常に更新できていましたが、更新数が一致しませんでした。

原因は SQL%ROWCOUNT?

更新パターン1,2 の両方を v_update_count に入れていたから?

別の更新数チェック方法

更新パターンごとに select count して更新前後で一致することを確認でOKです。

まとめ

一つのPL/SQLに複数パターンの更新内容を入れるとどうしても長くなり分かりにくくなりました。個人的には理由がなければ分けて実行した方がいいと思います。

コメント

タイトルとURLをコピーしました