第12回:ストアドプロシージャの移行(4) (2/2)

まるごと PostgreSQL!
PostgreSQLとOracleによるデータベース相互移行マニュアル

第12回:ストアドプロシージャの移行(4)
著者:奥畑 裕樹(OKUHATA, Hiroki)   2005/12/26
前のページ  1  2
フェッチ

   上述したカーソル属性同様、PostgreSQLではFETCH文の振る舞いも異なります。まずはOracleの例を見てください(リスト23)
DECLARE
  CURSOR C1 IS SELECT 顧客名 FROM 顧客マスタ;
  customer VARCHAR2(20);
BEGIN
  OPEN C1;
  FETCH C1 INTO customer;
  DBMS_OUTPUT.PUT_LINE( '顧客名= ' || customer );
  FETCH C1 INTO customer;
  DBMS_OUTPUT.PUT_LINE( '顧客名= ' || customer );
  FETCH C1 INTO customer;
  DBMS_OUTPUT.PUT_LINE( '顧客名= ' || customer );
  FETCH C1 INTO customer;
  DBMS_OUTPUT.PUT_LINE( '顧客名= ' || customer );
  FETCH C1 INTO customer;
  DBMS_OUTPUT.PUT_LINE( '顧客名= ' || customer );
  FETCH C1 INTO customer;
  DBMS_OUTPUT.PUT_LINE( '顧客名= ' || customer );
  CLOSE C1;
END;

リスト23:OracleのFETCH文の例

   Oracleでは最後の行に達した後も、FETCH文のターゲット変数がNULLになりません。実行結果を見てみましょう(図16)。

顧客名= (株)ワイキキソフト
顧客名= 鈴木商事
顧客名= 斎藤模型店
顧客名= マクロハード
顧客名= (株)ランヌ
顧客名= (株)ランヌ

PL/SQLプロシージャが正常に完了しました。

図16:リスト23の実行結果

   それに比べて、PostgreSQLでは最後の行に達した後は、FETCH文のターゲット変数にNULLが代入されます(リスト24)。

CREATE OR REPLACE FUNCTION TEST_FETCH()
  RETURNS VOID AS '
DECLARE
  C1 CURSOR IS SELECT 顧客名 FROM 顧客マスタ;
  customer VARCHAR(20);
BEGIN
  OPEN C1;
  FETCH C1 INTO customer;
  RAISE INFO ''顧客名= %'', customer;
  FETCH C1 INTO customer;
  RAISE INFO ''顧客名= %'', customer;
  FETCH C1 INTO customer;
  RAISE INFO ''顧客名= %'', customer;
  FETCH C1 INTO customer;
  RAISE INFO ''顧客名= %'', customer;
  FETCH C1 INTO customer;
  RAISE INFO ''顧客名= %'', customer;
  FETCH C1 INTO customer;
  RAISE INFO ''顧客名= %'', customer;
  CLOSE C1;
  RETURN;
END;
' LANGUAGE 'plpgsql';

SELECT TEST_FETCH();

リスト24:PostgreSQLのFETCH文の例

   さきほどのOracleの実行結果(図16)と図17を比べてください。

INFO: 顧客名= (株)ワイキキソフト
INFO: 顧客名= 鈴木商事
INFO: 顧客名= 斎藤模型店
INFO: 顧客名= マクロハード
INFO: 顧客名= (株)ランヌ
INFO: 顧客名= <NULL>
 test_fetch
------------

(1 row)

図17:リスト24の実行結果


   この微妙な振る舞いの違いがあるため、PostgreSQLではリスト25にあるような、Oracleでよく使われるループの書き方ができません。

DECLARE
  CURSOR C1 IS SELECT 顧客名
    FROM 顧客マスタ ORDER BY 顧客ID;
  NAME VARCHAR2(20);
BEGIN
  OPEN C1;
  LOOP
    FETCH C1 INTO NAME;
    EXIT WHEN C1%NOTFOUND;
  END LOOP;
  DBMS_OUTPUT.PUT_LINE( '顧客IDが一番大きい顧客= ' || NAME );
  CLOSE C1;
 END;

リスト25:Oracleでのループ例

   リスト25の実行結果は次のようになります。

顧客IDが一番大きい顧客 = (株)ランヌ
   このため、PostgreSQLではリスト26のようにフェッチ結果の変数への代入を2段階に分ける必要があります。

CREATE OR REPLACE FUNCTION TEST_FETCH2()
RETURNS VOID AS '
  DECLARE
    C1 CURSOR IS SELECT 顧客名
      FROM 顧客マスタ ORDER BY 顧客ID;
    NAME TEXT;
    _NAME TEXT;
  BEGIN
    OPEN C1;
    LOOP
      FETCH C1 INTO _NAME;
      IF NOT FOUND THEN
        EXIT;
      ELSE
        NAME := _NAME;
      END IF;
    END LOOP;
    RAISE INFO ''顧客IDが一番大きい顧客= %'', NAME;
    CLOSE C1;
    RETURN;
  END;
 ' LANGUAGE 'plpgsql';

 SELECT TEST_FETCH2();

リスト26:PostgreSQLでのフェッチ結果の代入例

   これは、PostgreSQLでは次のように単純に変換してしまうと、ループを抜けた後のNAME変数の中身が最後のフェッチ内容ではなくNULLになってしまうためです。

LOOP
  FETCH C1 INTO NAME;
  EXIT WHEN NOT FOUND;
END LOOP;
RAISE INFO ''顧客IDが一番大きい顧客= %'', NAME;
前のページ  1  2


奥畑 裕樹(OKUHATA, Hiroki)
著者プロフィール
奥畑 裕樹(OKUHATA, Hiroki)
Javaとオープンソース技術を得意とする技術コンサルタント。最近のテーマは、ソフトウェア開発の全体最適をはかること。気が付けば、10才のときにプログラミングを始めて以来、常に何かを作っている…。


INDEX
第12回:ストアドプロシージャの移行(4)
  カーソル処理
フェッチ
PostgreSQLとOracleによるデータベース相互移行マニュアル
第1回 データベース移行
第2回 データの移行(1)
第3回 データの移行(2)
第4回 SQL文の移行(1)
第5回 SQL文の移行(2)
第6回 SSQL文の移行(3)
第7回 ファンクションの移行(1)
第8回 ファンクションの移行(2)
第9回 ストアドプロシージャの移行(1)
第10回 ストアドプロシージャの移行(2)
第11回 ストアドプロシージャの移行(3)
第12回 ストアドプロシージャの移行(4)
第13回 まとめ

人気記事トップ10

人気記事ランキングをもっと見る