2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Oracle PL/SQL カーソルの使用例

Posted at

#PL/SQL カーソルについて
PL/SQLにて、通常はSELECT文で抽出したデータを変数に代入して処理をするということがよくありますが、カーソルを使用すると、データベースの表から取り出した複数行を処理することができます。

##カーソル処理の流れ

CREATE [OR REPLACE] PROCEDURE
  ストアドプロシージャ名[(引数名 {IN | OUT | INOUT} データ型,...)]
IS
  カーソルの定義(CURSOR [カーソル名] IS [SELECT文])
BEGIN
  カーソルのオープン(OPEN [カーソル名])
  LOOP
    データの取得(FETCH [カーソル名] INTO [変数名])
  END LOOP;
  カーソルのクローズ(CLOSE [カーソル名])
END;

##カーソルの使用例

  1. 1件のデータを変数に格納する(カーソル処理とは異なるが、初歩的な事なので記述)
    必ずデータがある事を条件にINTO句で変数に挿入する

  2. 配列(索引付き変数)の操作
    項目数分の変数を用意する必要があるが、項目単位の操作が可能(7.のバルクバインド処理にも使える)

  3. レコード単位の操作
    FETCH INTO を使って1レコード単位で処理(通常、ループ文としてはあまり使えない)

  4. 索引付きレコード単位の操作
    レコード&項目の2元配列操作が可能

  5. カーソル・ループの操作
    OPEN,FETCH,CLOSEが省略可能(3.より便利)

  6. 暗黙カーソル
    直前のSQL実行結果が必要な場合に使える

  7. バルクバインド処理(1.のデータを違う表にセット)
    SQLエンジンを1回しか使用しない為、処理が高速

  8. WHILE文を使ったカーソル処理の例

CREATE PROCEDURE CURSOR_PROCEDURE(IX IN NUMBER,RESULT0 OUT CHAR,RESULT1 OUT CHAR,RESULT2 OUT CHAR,RESULT3 OUT CHAR,RESULT4 OUT CHAR,RESULT5 OUT CHAR,RESULT6 OUT CHAR)
IS
    CURSOR TABLE01_C IS SELECT HOGE,FUGA,ROWNUM A FROM TABLE01;

    TYPE TYP_TAB_1 IS TABLE OF TABLE01.HOGE%TYPE INDEX BY BINARY_INTEGER;             --pattern② 
    TYPE TYP_TAB_2 IS TABLE OF TABLE01.FUGA%TYPE INDEX BY BINARY_INTEGER;             --pattern② 
    TYPE TYP_REC_A IS RECORD(HOGE TABLE01.HOGE%TYPE,FUGA TABLE01.FUGA%TYPE,A NUMBER); --pattern③
    TYPE TYP_TAB_B IS TABLE OF TYP_REC_A INDEX BY BINARY_INTEGER;                     --pattern④

    TAB_1 TYP_TAB_1;    --pattern②
    TAB_2 TYP_TAB_2;    --pattern②
    REC_A TYP_REC_A;    --pattern③
    RECTAB_A TYP_TAB_B; --pattern④

    IX1 NUMBER:=1;      --pattern③
    IX2 NUMBER:=1;      --pattern④
    IX3 NUMBER;         --pattern⑥
    IX4 NUMBER:=1;      --pattern⑦
BEGIN

    /* ① 1件のデータを変数に格納する(カーソル処理とは異なるが、初歩的な事なので記述) */
    SELECT NVL(MAX(HOGE||FUGA),'NO_DATA')INTO RESULT0 FROM TABLE01 WHERE HOGE || FUGA || SECTION = 
    (SELECT HOGE||FUGA||SECTION FROM (SELECT HOGE,FUGA,SECTION,ROWNUM A FROM TABLE01) WHERE A = IX);


    /* ② 配列(索引付き変数)の操作 */
    FOR TABLE01_R IN TABLE01_C LOOP
        TAB_1(TABLE01_R.A):=TABLE01_R.HOGE;
        TAB_2(TABLE01_R.A):=TABLE01_R.FUGA;
    END LOOP;
    IF NOT(TAB_1.EXISTS(IX))THEN
       RESULT1:='NO_DATA';
    ELSE
       RESULT1:=TAB_1(IX)||TAB_2(IX);
    END IF;


    /* ③ レコード単位の操作 */
    RESULT2:='NO_DATA';
    OPEN TABLE01_C;
    LOOP
        FETCH TABLE01_C INTO REC_A;
        IF IX=IX1 THEN
           RESULT2:=REC_A.HOGE||REC_A.FUGA;
        END IF;
        EXIT WHEN TABLE01_C%NOTFOUND;
        IX1:=IX1+1;
    END LOOP;
    CLOSE TABLE01_C;


    /* ④ 索引付きレコード単位の操作 */
    FOR TABLE01_R IN TABLE01_C LOOP
        RECTAB_A(TABLE01_R.A):=TABLE01_R;
    END LOOP;
    IF NOT(RECTAB_A.EXISTS(IX))THEN
        RESULT3:='NO_DATA';
    ELSE
        RESULT3:=RECTAB_A(IX).HOGE||RECTAB_A(IX).FUGA;
    END IF;


    /* ⑤ カーソル・ループの操作 */
    RESULT4:='NO_DATA';
    FOR TABLE01_R IN TABLE01_C LOOP
        IF IX2=IX THEN
           RESULT4:=TABLE01_R.HOGE||TABLE01_R.FUGA;
           EXIT;
        END IF;
        IX2:=IX2+1;
    END LOOP;


    /* ⑥ 暗黙カーソル */
    UPDATE TABLE01 SET HOGE=HOGE WHERE HOGE || FUGA || SECTION = 
    (SELECT HOGE||FUGA||SECTION FROM (SELECT HOGE,FUGA,SECTION,ROWNUM A FROM TABLE01) WHERE A = IX);
    IF SQL%FOUND THEN
       RESULT5:=SQL%ROWCOUNT;
    ELSE
       RESULT5:='NO_DATA';
    END IF;

    /* ⑦ バルクバインド処理(①のデータを違う表にセット) */
    DELETE FROM TABLE01_TEST;
    FORALL IX3 IN 1..TAB_1.COUNT INSERT INTO TABLE01_TEST VALUES(TAB_1(IX3),TAB_2(IX3));


    /* ⑧ WHILE文を使ったカーソル処理の例 */
    RESULT6:='NO_DATA';
    OPEN TABLE01_C;
    FETCH TABLE01_C INTO REC_A;
    WHILE TABLE01_C%FOUND LOOP
        IF IX=IX4 THEN
           RESULT6:=REC_A.HOGE||REC_A.FUGA;
           EXIT;
        END IF;
        FETCH TABLE01_C INTO REC_A;
        IX4:=IX4+1;
    END LOOP;
    CLOSE TABLE01_C;

EXCEPTION
    WHEN OTHERS THEN ROLLBACK;
    DBMS_OUTPUT.PUT_LINE('Error: '||SQLERRM||'('||SQLCODE||')');
END;
/
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?