PostgreSQLエンタープライズ・コンソーシアム 技術部会 WG#2

WG2活動報告書
ストアドプロシージャ移⾏調査編(PostgreSQL 11版)

PostgreSQL Enterprise Consortium

⽬次
⽬次
1. 改訂履歴
2. ライセンス3. はじめに3.1. 本資料の⽬的
3.2. 本資料で記載する範囲
3.3. 本資料で扱う⽤語の定義
3.4. 本資料で扱うDBMSおよびツール
4. PostgreSQLのストアドプロシージャについて
4.1. PostgreSQLにおけるストアドプロシージャ
4.2. PL/pgSQLについて
5. OracleからPostgreSQLへの移⾏（定義関連）
5.1. CREATE PROCEDURE⽂5.2. CREATE PACKAGE⽂5.3. ALTER PROCEDURE⽂5.4. DROP PROCEDURE⽂
6. OracleからPostgreSQLへの移⾏（標準⼿続き⾔語関連）6.1. 構造
6.2. コメント
6.3. 引数6.4. データ型
6.5. 変数の宣⾔6.6. 制御構造
6.6.1. LOOP命令
6.6.2. WHILE命令
6.6.3. FOR命令
6.6.4. EXIT命令
6.6.5. CONTINUE命令
6.6.6. IF命令
6.6.7. CASE命令
6.6.8. GOTO命令
6.7. カーソル
6.7.1. カーソルの宣⾔
6.7.2. カーソルのOPEN
6.7.3. カーソルのFETCH
6.7.4. カーソルの終了判定
6.7.5. カーソルの更新
6.7.6. カーソルのCLOSE
6.7.7. REFCURSOR
6.8. エラーハンドリング
6.8.1. EXCEPTION⽂
6.8.2. RAISE⽂
7. OracleからPostgreSQLへの移⾏（その他）
7.1. 起動⽅法
7.2. プロシージャからの呼出⽅法
7.3. トランザクション制御
7.4. シーケンス
7.5. 組み込み関数
7.6. DUAL
7.7. パッケージ変数代替
8. 異種DBMSからPostgreSQLへの移⾏に関するまとめ
8.1. Oracleのユーティリティーパッケージについて
9. 著者

Page 2 of 20

2
4
5
6
6
6
6
6
7
7
7
8
8
8
9
9
10
10
10
10
10
11
11
11
11
12
12
12
12
13
13
13
13
13
14
14
14
14
14
15
15
15
16
16
16
16
17
17
17
17
19
19
20

PostgreSQL Enterprise Consortium

Page 3 of 20

PostgreSQL Enterprise Consortium

1. 改訂履歴
版

改訂⽇

変更内容

1.0

2013/03/25

新規作成

2.0

2014/03/26

2013 年度活動成果の追加

3.0

2018/03/16

4.0

2020/03/17

PostgreSQLの対象バージョンを10.3に更新「5.5. DROP FUNCTION⽂」の記述を変更「6.3. 引数」を追加「6.6.6. IF命令」の記述を変更「6.7.7. REFCURSOR」を追加「6.8.1. EXCEPTION⽂」にNO_DATA_FOUNDに関する注意点を追加「7.2. 呼出⽅法」を追加「7.4. シーケンス」を追加「7.5. 組み込み関数」を追加「7.6. DUAL」を追加「7.7. パッケージ変数代替」を追加

PostgreSQLの対象バージョンを11.6に更新「3. はじめに」からDB2、SQL Serverの記述を削除「4. PostgreSQLのストアドプロシージャについて」の記述を変更「5.1. CREATE FUNCTION⽂」を削除「5.1. CREATE PROCEDURE⽂」を追加「5.2. CREATE PACKAGE⽂」の記述を変更「5.3. ALTER FUNCTION⽂」を削除「5.3. ALTER PROCEDURE⽂」を追加「5.4. DROP FUNCTION⽂」を削除「5.4. DROP PROCEDURE⽂」を追加「6.3. 引数」の記述を変更「6.5. 変数の宣⾔」の記述を変更「6.7.7. REFCURSOR」の記述を変更「6.8.1. EXCEPTION⽂」のリンクを変更「7.1. 起動⽅法」の記述を変更「7.2. 呼出⽅法」を「7.2. プロシージャからの呼び出し⽅法」に変更「7.2. プロシージャからの呼び出し⽅法」の記述を変更「7.3. トランザクション制御」の記述を変更「8. 異種DBMSからPostgreSQLへの移⾏に関するまとめ」の記述を変更Page 4 of 20

PostgreSQL Enterprise Consortium

2. ライセンス
本作品はCC-BYライセンスによって許諾されています。 ライセンスの内容を知りたい⽅は こちら でご確認ください。 ⽂書の内容、表記に関する誤り、ご要望、感想等につきましては、PGEConsのサイト を通じてお寄せいただきますようお願いいたします。
Eclipseは、Eclipse Foundation,Inc.の⽶国、およびその他の国における商標もしくは登録商標です。
IBMおよびDb2は、世界の多くの国で登録されたInternational Business Machines Corporationの商標です。
Intel、インテルおよびXeonは、⽶国およびその他の国における Intel Corporation の商標です。
Javaは、Oracle Corporation 及びその⼦会社、関連会社の⽶国及びその他の国における登録商標です。 ⽂中の社名、商品名等は各社の商標または登録商標である場合があります。
Linux は、Linus Torvalds ⽒の⽇本およびその他の国における登録商標または商標です。
Red HatおよびShadowman logoは、⽶国およびその他の国におけるRed Hat,Inc.の商標または登録商標です。
Microsoft、Windows Server、SQL Server、⽶国 Microsoft Corporationの⽶国及びその他の国における登録商標または商標です。
MySQLは、Oracle Corporation 及びその⼦会社、関連会社の⽶国及びその他の国における登録商標です。 ⽂中の社名、商品名等は各社の商標または登録商標である場合があります。
Oracleは、Oracle Corporation 及びその⼦会社、関連会社の⽶国及びその他の国における登録商標です。 ⽂中の社名、商品名等は各社の商標または登録商標である場合があります。
PostgreSQLは、PostgreSQL Community Association of Canadaのカナダにおける登録商標およびその他の国における商標です。
Windows は⽶国 Microsoft Corporation の⽶国およびその他の国における登録商標です。
TPC, TPC Benchmark,TPC-C, TPC-E, tpmC, TPC-H, QphHは⽶国Transaction Processing Performance Councilの商標です
その他、本資料に記載されている社名及び商品名はそれぞれ各社が 商標または登録商標として使⽤している場合があります 。

Page 5 of 20

PostgreSQL Enterprise Consortium

3. はじめに3.1. 本資料の⽬的
本資料は、異種DBMSからPostgreSQLへストアドプロシージャを移⾏する作業の難易度およびボリュームの事前判断と、実際に書き換えを⾏う
際の参考資料として利⽤されることを想定しています。

3.2. 本資料で記載する範囲
本資料では、移⾏元の異種DBMSとしてOracle Databaseを想定し、PostgreSQLへストアドプロシージャを移⾏する際に書き換えが必要である
箇所とその書き換え⽅針について⼿続き⾔語を中⼼に記載します。スキーマ、SQL、組み込み 関数については本資料では取り扱っていません。
これらに関しては、それぞれ「スキーマ移⾏調査編」、「SQL移⾏調査編」、「組み込み関数移⾏調査編」を参照してください。

3.3. 本資料で扱う⽤語の定義
資料で記述する⽤語について以下に定義します。
表 3.1 ⽤語定義
No.

⽤語

意味

1

DBMS

データベース管理システムを指します。ここでは、PostgreSQLおよび異種DBMSの総称として利⽤します。

2

異種DBMS

PostgreSQL ではない、データベース管理システムを指します。本資料では、Oracle Database が該当します。

3

Oracleデータベース管理システムの Oracle Database を指します。

3.4. 本資料で扱うDBMSおよびツール
本書では以下のDBMSを前提にした調査結果を記載します。
表 3.2 本書で扱うDBMS
DBMS名称

バージョン

PostgreSQL

11.6

Oracle Database

11gR2 11.2.0.2.0

Page 6 of 20

PostgreSQL Enterprise Consortium

4. PostgreSQLのストアドプロシージャについて
データベースに対する⼀連の処理⼿順をまとめてDBMS内に格納する「ストアドプロシージャ」について、PostgreSQLにおける特徴を紹介します。

4.1. PostgreSQLにおけるストアドプロシージャ
PostgreSQL 11からは、Oracleと同様にプロシージャが利⽤可能です。
プロシージャの実⾏はEXECUTE⽂ではなく、CALL⽂を使⽤します。
処理ロジックの記述には、PostgreSQL専⽤の⼿続き⾔語としてPL/pgSQLが⽤意されています。
上記以外に、CやPerlなどで処理ロジックを組み込むことも可能です。
本資料では、PL/pgSQLで記述されるプロシージャに移⾏する場合について記載しています。

4.2. PL/pgSQLについて
PL/pgSQLは、OracleのPL/SQLと同様にSQLに制御構造（条件分岐やLOOP処理）などを組み込んだ、PostgreSQLで標準として実装されている
⼿続き⾔語です。
記述された処理ロジックは、ユーザ定義関数やプロシージャとしてデータベースに格納する事が出来ますが、事前にコンパイルはされずに、実⾏時に解釈され実⾏されます。

Page 7 of 20

PostgreSQL Enterprise Consortium

5. OracleからPostgreSQLへの移⾏（定義関連）
5.1. CREATE PROCEDURE⽂
表 5.1 CREATE PROCEDURE⽂の⽐較
OraclePostgreSQL

CREATE OR REPLACE PROCEDURE
プロシージャ名 (引数名 IN データ
型)
IS
変数名 データ型;
BEGIN
処理内容;
END [プロシージャ名];

CREATE OR REPLACE PROCEDURE
プロシージャ名 (引数名 IN データ型)
AS $$DECLARE
変数名 データ型;
BEGIN
処理内容;
END;
$$
LANGUAGE plpgsql;

PostgreSQLでは処理内容の記述部分（変数宣⾔とBEGINからENDまで）を⽂字列定数として作成する必要があります。
そのためにドル引⽤符付け（$$）を使って処理記述の範囲を囲います。
単⼀引⽤符で範囲を囲む⽅法も可能ですが、この場合にはプロシージャの本体部分で使⽤される単⼀引⽤符(')とバックスラッシュ(\)は⼆重にする必要があります。
処理内容の記述に使⽤している⾔語の指定が必須で、LANGUAGE句で指定します。
変数宣⾔部にDECLAREが必須ですので追加する必要があります。
引数を持たないPROCEDUREを作成するときにはOracleでは”()”を省略しますが、PostgreSQLでは”()”の記述が必須です。
上記以外ではIS → AS
OUT → INOUT
END [プロシージャ名]; → END;に書き換える必要があります。
PL/SQLではEND部分にPROCEDURE名を記述することがありますが、PL/pgSQLでは記述できません。

5.2. CREATE PACKAGE⽂PACKAGEは実装されていません。
FUNCTIONまたはPROCEDUREで代⽤することになります。
PACKAGEレベルで共通使⽤する定数などは、⼀時テーブルに保存するなどの⽅法を検討する必要があります。
PROCEDUREがPACKAGEに属している構成を元々とっていた場合には、SCHEMAで代替することができます。
表 5.2 PACKAGEとSCHEMAの⽐較
OracleCREATE OR REPLACE PACKAGE パッケージ名IS
PROCEDURE プロシージャ名 ((後略)

PostgreSQL

CREATE SCHEMA IF NOT EXISTS スキーマ名;
CREATE OR REPLACE PROCEDURE スキーマ名.プロシージャ名((後略)

SCHEMAを使⽤した場合は、PROCEDURE名にどのSCHEMAに属しているかを指定する必要があります。ひとつのPROCEDURE内で別のPROCEDUREを呼ぶ場合も同様にSCHEMAを指定する必要があります。
またPL/pgSQLでは仕様部と本体に分けず、⼀つのプロシージャ定義は⼀箇所に記述します。

Page 8 of 20

PostgreSQL Enterprise Consortium

5.3. ALTER PROCEDURE⽂
OracleとPostgreSQLでは互換性がありません。
Oracleでは再コンパイルに関する命令になります。
PostgreSQLではプロシージャ名の変更や所有者の変更などの、PROCEDUREが保持している情報を変更する命令になります。
PostgreSQLのPL/pgSQLは事前にコンパイルしておくことはできないため、代替機能はありません。

5.4. DROP PROCEDURE⽂
表 5.3 DROP PROCEDURE⽂の⽐較
OracleDROP PROCEDURE プロシージャ名;

PostgreSQLDROP PROCEDURE プロシージャ名 ( 引数名 IN データ型 );PostgreSQLでは、同名のプロシージャが存在している場合、引き渡しパラメータも含めて指定する必要があります。
パラメータの指定は引数名とデータ型の両⽅、もしくはデータ型のみでの記述が可能です。

Page 9 of 20

PostgreSQL Enterprise Consortium

6. OracleからPostgreSQLへの移⾏（標準⼿続き⾔語関連）
OracleとPostgreSQLにそれぞれ実装されている⼿続き⾔語である、PL/SQLとPL/pgSQLにおける記述の相違を中⼼に書換え⽅法を記述します。

6.1. 構造
構造のステートメントには相違ありません。
DECLARE
変数名 データ型;
BEGIN
処理内容
END;

「DECLARE部」で変数の宣⾔「BEGIN部」で処理内容の記述「END」でブロックの終了

6.2. コメント
コメントの記述には相違ありません。
-- コメント記述 ：⾏末までをコメントとします。
/* コメント記述 */ ：/* から */ までのブロック（複数⾏でも可）をコメントとします。

6.3. 引数
Oracleの引数の宣⾔ではIN引数、OUT引数、IN OUT引数を使⽤することができますが、PostgreSQLではIN引数またはINOUT引数のみ使⽤することができます。
OUT引数を使⽤していた場合はINOUT引数に書き換える必要があります。

INOUT引数プロシージャの呼び出し⽅<INOUT引数を持つプロシージャ>
CREATE OR REPLACE PROCEDURE プロシージャ名(変数名 INOUT データ型)...
<呼び出し元の宣⾔部>
変数 データ型;<呼び出し部分>
CALL プロシージャ名(変数);

また、上記以外の細かな違いとして、引数に対してデフォルトの値を設定する際に := ではなく = を使うというものがあります。
OraclePostgreSQL

CREATE OR REPLACE PROCEDURE プロシージャ名 (変数名 データ型 := デフォルト値...

CREATE OR REPLACE PROCEDURE プロシージャ名 (変数名 IN データ型 = デフォルト値...

6.4. データ型
PostgreSQLで使⽤可能なデータ型はPL/pgSQLで使⽤できます。
データ型の変換については別ドキュメント「組み込みデータ型対応表（Oracle-PostgreSQL）」を参照してください。
同様に%ROWTYPE型や%TYPEはそのまま使⽤できます。

Page 10 of 20

PostgreSQL Enterprise Consortium

RECORD型については注意が必要です。
OraclePostgreSQL

type 変数名 is RECORD (変数名 データ型);

変数名 RECORD;

PL/pgSQLではRECORD型の宣⾔時にはレコードの内容は記述しません。
レコードの内容は直接SELECT⽂を記述したり、カーソルのFETCHで使⽤されると定義が確定されます。
例１. SELECTの結果をレコード型にストアする
rec_name IN SELECT C1, C2 FROM tb1
例２. カーソルcuの結果をレコード型にストアする
fetch cu into rec_name
データ型のキャストには組み込み関数を使⽤することも可能ですが、PostgreSQLでは伝統的に「::」を使⽤してキャストを⾏います。
Oracleで⽤意されている型キャストの関数の中にはPostgreSQLでは存在しないものもあります。
表 6.1 型キャストの⽐較
Oracle

変数 := TO_NUMBER(値);
変数 := TO_CHAR(値);PostgreSQL

変数 := 値::numeric;
変数 := 値::text;

NULL に関してもOracleとPostgreSQLでは違いがありますので注意が必要になります。NULLについては別ドキュメント「SQL移⾏調査編」を参照してください。
テーブル型はOracleでは宣⾔する必要がありますが、PostgreSQLではテーブルを定義した時点でそのテーブル名と同名のものが利⽤できるようになるため、宣⾔する必要がありません。

6.5. 変数の宣⾔プログラム内で使⽤する変数は必ず宣⾔部に記述して宣⾔を⾏う必要があります。
但し、例外としてFORループで使⽤するループ変数はこの限りではありません。
また、例外の名前の宣⾔はPL/pgSQLでは宣⾔する事が出来ません。

6.6. 制御構造
6.6.1. LOOP命令
LOOPの記述には相違ありません。
LOOP
繰り返し処理;EXIT WHEN 条件式;
END LOOP;「LOOP」と「END LOOP」の間に記述された命令を繰り返し実⾏します。
LOOPを抜けるためにはEXITを使⽤します。
EXITに続けてLOOPを抜ける条件式を記述します。
EXITのみでは無条件でLOOPから抜けます。

6.6.2. WHILE命令
WHILEの記述には相違ありません。

Page 11 of 20

PostgreSQL Enterprise Consortium

WHILE 条件式 LOOP
繰り返し処理;END LOOP;「WHILE」と「LOOP」の間に繰り返しの条件式を記述し、「END LOOP」の間に繰り返す命令を記述します。
条件式を満たす前にLOOPを抜けるためにはEXITを使⽤します。

6.6.3. FOR命令
FORの記述には相違ありません。
FOR 変数名 IN 1 .. 10 LOOP
繰り返し処理;END LOOP;

INの後に記述した最⼩値から最⼤値までの間、「LOOP」から「END LOOP」に記述された命令を繰り返し実⾏します。
但し、「REVERSE」を使って値を最⼤値から最⼩値までを⾏う場合には書換えが必要です。
OraclePostgreSQL

FOR 変数名 IN REVERSE 1 .. 10 LOOP
繰り返し処理;END LOOP;

FOR 変数名 IN REVERSE 10 .. 1 LOOP
繰り返し処理;END LOOP;

最⼤値と最⼩値の値の指定が逆になります。

6.6.4. EXIT命令
EXITの記述には相違ありません。
EXIT;
EXIT [ ラベル名 ] ;EXIT WHEN A1 > 10;

ラベルが指定されない場合には最も内側のLOOPを終わらせます。
ラベルの指定がある場合には指定されたラベルのループを抜けます。
WHENが指定された場合には、条件式を満たしていればEXITを実⾏します。

6.6.5. CONTINUE命令
CONTINUEの記述には相違ありません。
CONTINUE;
CONTINUE [ ラベル 名 ] ;CONTINUE WHEN 条件式;

ラベルが指定されない場合には実⾏しているLOOPの先頭に戻り次の反復に制御を移します。
ラベルの指定がある場合には指定されたラベルの先頭に戻り次の反復に制御を移します。
WHENが指定された場合には、条件式を満たしていればCONTINUEを実⾏します。

6.6.6. IF命令

Page 12 of 20

PostgreSQL Enterprise Consortium

IF⽂については、Oracleの記述と相違ありません。

6.6.7. CASE命令
CASEの記述には相違ありません。
CASE 変数WHEN 条件値 THEN
分岐処理
ELSE
分岐処理
END CASE;

WHEN句内の値と⽐較を⾏い⼀致すれば指定された命令が実⾏されます。
全てのWHENを順番に評価した後⼀致するものがない場合、ELSEの命令を実⾏します。
⼀致するWHENがなくELSEの記述が無い場合には、CASE_NOT_FOUND例外が発⽣します

6.6.8. GOTO命令
PostgreSQLにはGOTO命令がありません。
OraclePostgreSQL[対応する命令なし]

GOTO ラベル ;置換える命令がありません。
無条件に指定したラベルに制御を移すことは出来ません。

6.7. カーソル
6.7.1. カーソルの宣⾔
カーソルの宣⾔については注意が必要です。
OracleCURSOR カーソル名 IS クエリー;

PostgreSQL

カーソル名 CURSOR FOR クエリー;

どちらも宣⾔はDECLARE部で⾏いますが、⽂法が違います。
FORの部分はISで記述されていても⽂法エラーにはなりません。
また引数を宣⾔する際にINというキーワードがPL/pgSQLでは不要になります。
OraclePostgreSQLCURSOR カーソル名 (引数 IN データ型) IS ...

カーソル名 CURSOR (引数 データ型) FOR ...

6.7.2. カーソルのOPEN
カーソルのOPENの記述には相違ありません。
OPEN カーソル名;宣⾔をしたカーソルから⾏を取り出すために、OPENによりカーソルを開きます。

Page 13 of 20

PostgreSQL Enterprise Consortium

6.7.3. カーソルのFETCH
カーソルのFETCHの記述には相違ありません。
FETCH カーソル名 INTO 取得した値を格納する変数;
カーソルから⾏を1⾏づつ取り出して変数に格納します。

6.7.4. カーソルの終了判定
カーソルをすべてFETCHしたときの判定⽅法は注意が必要です。
Oracleカーソル名%NOTFOUND;

PostgreSQLNOT FOUND;

Oracleでは、カーソル名を明⽰して終了判定（NOTFOUND）しますが、PostgreSQLではカーソル名の指定はできません。

6.7.5. カーソルの更新
カーソルのカレント⾏に対する更新の記述には相違ありません。
＜更新＞
UPDATE テーブル名 SET 更新内容 WHERE CURRENT OF カーソル名;＜削除＞
DELETE FROM テーブル名 WHERE CURRENT OF カーソル名;
カーソルの宣⾔時にFOR UPDATEを使って作成したカーソルの現在⾏に対して項⽬の値の変更およびレコードの削除を⾏います。

6.7.6. カーソルのCLOSE
カーソルのCLOSEの記述には相違ありません。
CLOSE カーソル名;OPENしたカーソルを閉じます。
PL/pgSQLには%ISOPENが存在していません。PL/SQLではカーソルの閉じ忘れ防⽌としても使⽤していましたが、PL/pgSQLではそれができません。
クローズを忘れないようにすれば問題ありませんが、%ISOPENの代⽤としては以下の⽅法があります。

BEGIN
CLOSE カーソル名;
EXCEPTION
WHEN invalid_cursor_name THEN NULL;
END;

すでにクローズされたカーソルをクローズしようとするとエラーが発⽣しますが、それを例外として拾いそこでは何もしないという処理をしています。オープンの状態であればクローズし、クローズされていれば何もしません。

6.7.7. REFCURSOR
プロシージャの引数や変数としてカーソルを使⽤する場合は、refcursor型として宣⾔します。
PL/SQLではSYS_REFCURSORと宣⾔されていたものです。

Page 14 of 20

PostgreSQL Enterprise Consortium

CREATE OR REPLACE PROCEDURE プロシージャ名 ()AS $$DECLARE
カーソル名 refcursor;
BEGIN
(処理)
END;

6.8. エラーハンドリング
6.8.1. EXCEPTION⽂EXCEPTIONの記述には相違ありません。
EXCEPTION
WHEN エラーコード（もしくは例外名） 1 THEN エラー処理内容１
WHEN エラーコード（もしくは例外名） 2 THEN エラー処理内容2
WHEN OTHERS
THEN エラー処理内容3
END;

WHENの後に記述された例外の内容と合致したときにTHENの後に記述された処理を⾏います。
指定された例外以外が発⽣したときは、呼び出し元にエラー情報が伝搬します。
例外に設定されている名前に相違があるものは個別に書換えが必要です。
以下は例外の⼀部についての対⽐をまとめましたので、参考にしてください。
Oracleの例外名

PostgreSQLの例外名

相違

CASE_NOT_FOUND

CASE_NOT_FOUND

同じ

INVALID_CURSORINVALID_CURSOR_STATE

書換え必要

NO_DATA_FOUND

NO_DATA_FOUND

同じ*1

STORAGE_ERROROUT_OF_MEMORY

書換え必要

TOO_MANY_ROWS

TOO_MANY_ROWS

同じ

ZERO_DIVIDEDIVISION_BY_ZERO

書換え必要

なお、PostgreSQLのエラーコードに対する例外名はマニュアルの付録に記載があるので参考にしてください。
https://www.postgresql.jp/document/11/html/errcodes-appendix.html*1 NO_DATA_FOUND に関して注意すべき点があります。
OracleではSELECTの結果が0であった場合にこの例外に該当しますが、PostgreSQLでは明⽰的にハンドリングしなければSELECTの結果が0⾏であっても例外として判断されません。
SELECT INTO⽂にSTRICTを加えるかもしくは代⼊先の変数がNULLであるかを確認して例外を投げる必要があります。

6.8.2. RAISE⽂RAISEを使った例外を発⽣させる記述には相違ありません。
RAISE exception;

事前定義の例外を明⽰的に呼び出します。
但し、Oracleでは宣⾔部で例外の名前を宣⾔して、RAISEで例外を呼び出せますが、PostgreSQLでは宣⾔部での名前の宣⾔が出来ないので、
RAISE⽂で例外の詳細を記述する事になります。
代替として、任意のSQLSTATE(5⽂字の状態コード)を使⽤することができます。
PL/pgSQL関連の例外はP0から始まるのが作法ですが、最低限マニュアルにも記載されている規定のSQLSTATEと重複しなければ問題ありません。

Page 15 of 20

PostgreSQL Enterprise Consortium

7. OracleからPostgreSQLへの移⾏（その他）
7.1. 起動⽅法
実⾏⽅法については注意が必要です。
OraclePostgreSQLEXECUTE プロシージャ名

CALL プロシージャ名();

PostgreSQLではCALL⽂を使⽤してプロシージャを呼び出します。
また、Oracleでは引数がない場合には括弧は不要ですが、PostgreSQLでは括弧が必要です。

7.2. プロシージャからの呼出⽅法
プロシージャの中で別のプロシージャを実⾏する場合、以下のように呼び出します。

(text型のINOUT引数を持つプロシージャを呼ぶ場合)
CREATE OR REPLACE PROCEDURE プロシージャ名()AS $$DECLARE
変数 text;
BEGIN
CALL 呼び出すプロシージャ名(変数);END;$$
LANGUAGE plpgsql;

7.3. トランザクション制御
PostgreSQLのストアドプロシージャでもトランザクション制御が可能です。
ただし、例外ハンドラを伴うブロック内では使⽤できないなど、Oracleに⽐べて使⽤できる場所に制限があります。

例えば、以下のような場合はCOMMIT部分でエラーになります。
CREATE OR REPLACE PROCEDURE プロシージャ名(...)
AS $$
BEGIN
処理1
COMMIT; /* エラー */処理2
EXCEPTIONROLLBACK; /* 正常実⾏可能 */
例外処理
END;
$$
LANGUAGE plpgsql;
また、他にも以下のような違いがあります。
プロシージャ内でエラーが発⽣した場合、Oracleの場合はエラーより前の処理を例外処理部でコミットすることができますが、PostgreSQLではエラーの発⽣したプロシージャ内で、コミットされていない処理は全てロールバックされます。
PostgreSQLで例外処理部(EXCEPTION句)の中でコミットした場合、EXCEPTION句内でコミットより前に記述した処理と、プロシー
ジャの呼び出し元で実⾏された処理をコミットします。
プロシージャが⼊れ⼦になっていて、親プロシージャにEXCEPTION句がある場合は、トランザクション制御を含む⼦プロシージャを実⾏部(BEGINブロック)から呼ぶことはできません。

Page 16 of 20

PostgreSQL Enterprise Consortium

7.4. シーケンス
PostgreSQLとOracleでは、シーケンスから値を取り出す構⽂が異なります。
以下がPostgreSQLでのシーケンス値の取り出し⽅です。

nextval('シーケンス名')-- 次の値を取り出す
setval('シーケンス名', 値) -- 値をセットする
currval('シーケンス名')-- 現在値を再度取り出す

その他シーケンス移植時の情報は別ドキュメント「DB移⾏開発⾒積り編」も参照ください。

7.5. 組み込み関数
組み込み関数に関しても書き換えが必要になる部分があります。
これに関しては別ドキュメント「組み込み関数移⾏調査編」を参照ください。

7.6. DUAL
PostgreSQLではOracleのようにDUALテーブルは⽤意されていません。
対応⽅法に関しては別ドキュメント「SQL移⾏調査編」を参照ください。

7.7. パッケージ変数代替
PostgreSQLではパッケージという概念が無いためPL/SQLのパッケージ変数をそのまま移植することができません。PL/pgSQLでそれを実現させるためにはいくつか⽅法があるかもしれませんが、ここでは⼀時テーブルを使⽤したものを紹介します。PostgreSQLの⼀時テーブルは接続ごとに独⽴して作成され、接続が切断されるとテーブル定義はそのデータと共に消えます。
これを実現させるためにはその⼀時テーブルの作成とテーブルへのデータ挿⼊、更新そしてデータの取得を⾏うための関数もしくはプロシージャ
をパッケージごとに作成する必要があります。PostgreSQLではパッケージという概念がないためスキーマを代わりに使⽤している前提となります。

(初期化⽤関数例)
CREATE OR REPLACE FUNCTION スキーマ名.初期化⽤ファンクション名 ()RETURNS void LANGUAGE plpgsql
AS $$DECLARE
変数 INTEGER := 0;
BEGIN
SELECT INTO 変数 count(*) FROM information_schema.tables WHERE table_name = lower('⼀時テーブル名');
IF 変数 = 0 THEN
CREATE TEMP TABLE ⼀時テーブル名 (key TEXT, val TEXT);
INSERT INTO ⼀時テーブル名 VALUES('パッケージ変数名1','値1'),('パッケージ変数名2','値2'),...;
END IF;
END;$$;

すでに⼀時テーブルが存在していないことを確認し、⼀時テーブルを作成します。テーブル内の列は2つでkeyに変数名を格納し、valにその変数の値を格納します。変数の値は⼀旦⽂字列として保存し取り出す際にあるべきデータ型にキャストすることになります。

Page 17 of 20

PostgreSQL Enterprise Consortium(登録⽤関数)CREATE OR REPLACE FUNCTION スキーマ名.登録⽤ファンクション名 (登録する変数 TEXT, 登録する値 TEXT)RETURNS void LANGUAGE plpgsql
AS $$DECLARE
更新する⼀時テーブル名 TEXT := '⼀時テーブル名';
変数 INTEGER := 0;BEGIN
PERFORM スキーマ名.初期化⽤ファンクション名 ();EXECUTE 'SELECT count(*) FROM ' || quote_ident(更新する⼀時テーブル名) || ' WHERE key = $1' INTO 変数 USING 登録する変数;
IF 変数 = 0 THENEXECUTE 'INSERT INTO ' || quote_ident(更新する⼀時テーブル名) || ' VALUES ($1, $2)' USING 登録する変数, 登録する値;
ELSE
EXECUTE 'UPDATE ' || quote_ident(更新する⼀時テーブル名) || ' SET val = $1 WHERE key = $2' USING 登録する値, 登録する変数;
END IF;
END;$$;

初期化⽤の関数を実⾏することですでにテーブルができている状態を確⽴します。条件分岐ではもし⼀時テーブル内に登録しようとしている変数が存在していなければ新規登録を⾏い、すでに存在している場合は更新を⾏うようになっています。

(取得⽤関数)CREATE OR REPLACE FUNCTION スキーマ名.取得⽤ファンクション名 (値を取得したい変数 TEXT)RETURNS TEXT LANGUAGE plpgsql
AS $$DECLARE
取得する⼀時テーブル名 TEXT := '⼀時テーブル名';
取得した値⽤変数 TEXT := NULL;BEGINPERORM スキーマ名.初期化⽤ファンクション名 ();EXECUTE 'SELECT val FROM ' || quote_ident(取得する⼀時テーブル名) || ' WHERE key = $1' INTO 取得した値⽤変数 USING 値を取得したい変数;RETURN 取得した値⽤変数;
END;
$$;

上記3つの関数を使⽤することでDBへの接続ごとに値を保持することが可能になり関数間で使い回すことが可能になります。
ただし、PL/SQLの場合は関数内でROLLBACKが実⾏された場合でもパッケージ変数の値は保たれますが、上記の⽅法ではそれを実現できていないことに注意してください。

Page 18 of 20

PostgreSQL Enterprise Consortium

8. 異種DBMSからPostgreSQLへの移⾏に関するまとめ
SQLレベルであったり⼿続き⾔語の構⽂については、ある程度単純な置換え作業は可能と思われます。
しかし業務処理を移⾏するためには以下の様な問題があります。
PostgreSQLでは呼び出し⽅法が変わる
異種DBMSの個別機能（例えばOracleのパッケージなど）の対応が複雑もしくは代替⼿段がない
トランザクション制御の機能に制限がある
このような状況を考えると、単純に移⾏が出来る異種DBMSのストアドプロシージャは限られてくるものと思われます。
もう⼀つPL/pgSQLの特徴として、実⾏時にソースの解析が⾏われます。
異種DBMSに実装されている事前コンパイル機能などにより、実⾏レスポンスを向上させる⽬的で使⽤しているのであれば、この部分においては移⾏前と同等の性能は期待できない可能性があります。
これらを総合すると処理の内容によっては、異種DBMSのストアドプロシージャは、PL/pgSQLに移⾏するよりも他の⾔語で実装する⽅が容易になる可能性があります。

8.1. Oracleのユーティリティーパッケージについて
Oracleのストアドプロシージャでは、ユーティリティパッケージ（DBMS_OUTPUTやUTL_FILE）がよく使⽤されていますが、これらはOracle
が提供しているのでPostgreSQLには実装されていません。
DBMS_OUTPUTは同様の機能としてRAISE NOTICEで代⽤できるものもありますが、構⽂が違うので個別での対応が必要と思われます。
参考ですがOrafceではユーティリティーパッケージの⼀部の実装を実現しています。
但し、仕様的にOracleとの違いがありますので注意が必要です。
例）DBMS_OUTPUTの通知のタイミング
Oracle トランザクションの終了時
Orafce 送信都度

Page 19 of 20

PostgreSQL Enterprise Consortium

9. 著者
版

所属企業・団体名

部署名

⽒名

ストアドプロシージャ移⾏調査編
第2版（2013年度 WG2）

クオリカ株式会社

開発センター

坂本 浩⾏

インフォメーションクリエーティブ株式会社

ソリューション開発本部

林⽥ ⻯⼀

ストアドプロシージャ移⾏調査編
第3版（2017年度 WG2）SRA OSS, Inc. ⽇本⽀社

OSS 事業本部

佐藤 友章

SRA OSS, Inc. ⽇本⽀社

OSS 事業本部

千⽥ 貴⼤

ストアドプロシージャ移⾏調査編
第4版（2019年度 WG2）

富⼠通株式会社

ソフトウェア事業本部

佐藤 光洋

富⼠通株式会社

ソフトウェア事業本部

⻄垣 雅樹

富⼠通株式会社

ソフトウェア事業本部

豊島 良美

Page 20 of 20