PL/SQL で SELECT INTO を行なう

テーブル定義

テーブルは PLSQL による INSERT のテーブル定義をデータ使用

PL/SQL で SELECT を実行する

PL/SQL で SELECT を行なうには SELECT 〜 INTO を使用して SELECT の結果を変数に代入しなければならない。 SELECT だけを単独で記述すると以下のコンパイルエラーが出力される。

PLS-00428: INTO 句はこの SELECT 文に*入ります*。
(これは「要ります」の誤りと思われる)
PLS-00428: an INTO clause is expected in this SELECT statement (英文)

SELECT INTO を使用した単一行の取得

  1. CREATE OR REPLACE PROCEDURE RIVUS.STEP01_SELECT
  2. IS
  3.     vUserID USER_MASTER.USER_ID%TYPE;
  4.     vUserName USER_MASTER.USER_NAME%TYPE;
  5. BEGIN
  6.     SELECT USER_ID, USER_NAME INTO vUserID, vUserName FROM USER_MASTER;
  7.  
  8.     DBMS_OUTPUT.PUT_LINE('利用者IDは' || vUserID || 'です。');
  9.     DBMS_OUTPUT.PUT_LINE('利用者名は' || vUserName || 'さんです。');
  10. END;
  11. /
-- 実行してみる。
SQL> SET SERVEROUTPUT ON
SQL> CALL STEP01_SELECT();
利用者IDは0020です。
利用者名は小泉 純一さんです。
 
コールが完了しました。

しかし、このプログラムは抽出対象レコードが単一の場合しか使用できない。複数件になると以下のエラーが出力される。

SQL> INSERT INTO USER_MASTER ( USER_ID, USER_NAME) VALUES ('1000', 'おじゃまデータ');
1行が作成されました。
 
SQL> CALL STEP01_SELECT();
     *
行1でエラーが発生しました。:
ORA-01422: 完全フェッチがリクエストよりも多くの行を戻しました
ORA-06512: "RIVUS.STEP01_SELECT", 行6
SQL> ROLLBACK;
ロールバックが完了しました。

(補足)データが 0 件、または、複数件のときの例外処理を作成することで処理を継続させることができる。

CREATE OR REPLACE PROCEDURE RIVUS.STEP01_SELECT
IS
    vUserID	USER_MASTER.USER_ID%TYPE;
    vUserName	USER_MASTER.USER_NAME%TYPE;
BEGIN
    SELECT USER_ID, USER_NAME INTO vUserID, vUserName FROM USER_MASTER;
 
    DBMS_OUTPUT.PUT_LINE('利用者IDは' || vUserID || 'です。');
    DBMS_OUTPUT.PUT_LINE('利用者名は' || vUserName || 'さんです。');
/***** ここから例外処理 *****/
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    DBMS_OUTPUT.PUT_LINE('データが見つかりませんでした。');
  WHEN TOO_MANY_ROWS THEN
    DBMS_OUTPUT.PUT_LINE('データが複数見つかりました。');
/***** ここまで例外処理 *****/
END;
/

詳細は PLSQL の例外処理

複数のレコードを取り扱う

複数のレコードを取り扱うには カーソル・ループ を使う方法と コレクションを使用した バルク処理(バルクフェッチ) による方法がある。 複数のデータを一度に処理するケースではバルク処理の方が IO 回数が少ないために高速に処理を行うことができる。

SELECT BULK COLLECT INTO によるバルク処理

複数レコードを一括で取り扱うには SELECT BULK COLLECT INTO を使用する。この構文は比較的小さな結果セットを取り扱う場合に有用である。結果セットが一度にメモリ中で取り扱うには大きすぎる場合には、より多くの組み込みが必要ではあるが バルクフェッチ を使用したほうが良い。

CREATE OR REPLACE PROCEDURE RIVUS.STEP01_SELECT_ALL
IS
    TYPE	tUserList	IS TABLE OF USER_MASTER%ROWTYPE;
    vUsers			tUserList;
BEGIN
    SELECT * BULK COLLECT INTO vUsers FROM USER_MASTER;
    --        ↑ コレクション(ネストした表) vUsers にすべての結果が一度に設定される。
    DBMS_OUTPUT.PUT_LINE('レコード数は' || vUsers.COUNT || '件です。');
    DBMS_OUTPUT.PUT_LINE('利用者IDは' || vUsers(1).USER_ID || 'です。');
    DBMS_OUTPUT.PUT_LINE('利用者名は' || vUsers(1).USER_NAME || 'さんです。');
 
    vUsers.DELETE; -- 要らなくなったから解放
    DBMS_OUTPUT.PUT_LINE('配列の大きさは' || vUsers.COUNT || 'です。');
END;
/
 


関連事項

日本オラクル
■ 日本オラクル 株式会社
■ オラクルマスター資格 (オラクルマスターとは
■ Oracle のライセンスがわからない…
Oracle Direct (ネットで聞いても最後はここで要確認)