版 | 改訂日 | 変更内容 |
---|---|---|
1.0 | 2013/03/25 | 新規作成 |
2.0 | 2014/03/26 | 2013 年度活動成果の追加 |
3.0 | 2018/03/16 |
|
本作品はCC-BYライセンスによって許諾されています。 ライセンスの内容を知りたい方は こちら でご確認ください。 文書の内容、表記に関する誤り、ご要望、感想等につきましては、PGEConsのサイト を通じてお寄せいただきますようお願いいたします。
本資料は、異種DBMSからPostgreSQLへストアドプロシージャを移行する作業の難易度およびボリュームの事前判断と、実際に書き換えを行う際の参考資料として利用されることを想定しています。
資料で記述する用語について以下に定義します。
No. | 用語 | 意味 |
---|---|---|
1 | DBMS | データベース管理システムを指します。ここでは、PostgreSQLおよび異種DBMSの総称として利用します。 |
2 | 異種DBMS | PostgreSQL ではない、データベース管理システムを指します。本資料では、Oracle Database、IBM DB2 および Microsoft SQLServer が該当します。 |
3 | Oracle | データベース管理システムの Oracle Database を指します。 |
4 | DB2 | データベース管理システムの IBM DB2 を指します。 |
5 | SQLServer | データベース管理システムの Microsoft SQLServer を指します。 |
データベースに対する一連の処理手順をまとめてDBMS内に格納する、 「ストアドプロシージャ」についてPostgreSQLにおける特徴を紹介します。
Oracle | PostgreSQL |
---|---|
CREATE OR REPLACE FUNCTION
ファンクション名 (@引数名 IN データ型)
RETURN 戻り値データ型
IS
変数名 データ型;
BEGIN
処理内容;
END [ファンクション名];
|
CREATE OR REPLACE FUNCTION
proc_f ( 引数名 IN データ型 )
RETURNS 戻り値データ型
AS
$$
DECLARE
変数名 データ型;
BEGIN
処理内容;
END;
$$
LANGUAGE plpgsql;
|
RETURN → RETURNSIS → ASEND [FUNCTION名]; → END;
Oracle | PostgreSQL |
---|---|
CREATE OR REPLACE PACKAGE パッケージ名
IS
PROCEDURE プロシージャ名 (
(後略)
|
CREATE SCHEMA IF NOT EXISTS スキーマ名;
CREATE OR REPLACE FUNCTION スキーマ名.ファンクション名 (
(後略)
|
OracleとPostgreSQLにそれぞれ実装されている手続き言語である、PL/SQLとPL/pgSQLにおける記述の相違を中心に書換え方法を記述します。
構造のステートメントには相違ありません。
DECLARE
変数名 データ型;
BEGIN
処理内容
END;
コメントの記述には相違ありません。
-- コメント記述 :行末までをコメントとします。/* コメント記述 */ :/* から */ までのブロック(複数行でも可)をコメントとします。
同名になってしまうOUT引数付き関数
同名で同引数を持つ関数を複数作成できないことはOracleでもPostgreSQLでも同じですが、PostgreSQLはこの判断にOUT引数を考慮しません。したがって、引数の数や名前が違う場合でもそれらがOUT引数である場合、同名で同引数の関数と判断され作成時にエラーとなります。
OUT引数関数の呼び出し方
OUT引数(INOUT引数)を持つ関数を呼び出す場合、OUT引数は呼出引数に含めず返り値を引数に代入するように記述する必要があります。 また、複数OUT引数がある場合は一旦RECORD型に代入する必要があります。
<複数のOUT引数を持つ関数>
CREATE OR REPLACE ファンクション名 (
引数1 IN データ型,
引数2 OUT データ型,
引数3 OUT データ型
) LANGUAGE plpgsql ...
<呼び出し元の関数宣言部に以下を追加>
変数1 RECORD;
<呼び出し部分>
変数1 := ファンクション名(引数1);
Oracle | PostgreSQL |
---|---|
PROCEDURE プロシージャ名 (
変数名 データ型 := デフォルト値
...
|
CREATE OR REPLACE FUNCTION ファンクション名 (
引数1 IN データ型 = デフォルト値
...
|
RECORD型については注意が必要です。
Oracle | PostgreSQL |
---|---|
type 変数名 is RECORD (
変数名 データ型
);
|
変数名 RECORD;
|
Oracle | PostgreSQL |
---|---|
変数 := TO_NUMBER(値);
変数 := TO_CHAR(値);
|
変数 := 値::numeric;
変数 := 値::text;
|
LOOPの記述には相違ありません。
LOOP
繰り返し処理;
EXIT WHEN 条件式;
END LOOP;
WHILEの記述には相違ありません。
WHILE 条件式 LOOP
繰り返し処理;
END LOOP;
FORの記述には相違ありません。
FOR 変数名 IN 1 .. 10 LOOP
繰り返し処理;
END LOOP;
Oracle | PostgreSQL |
---|---|
FOR 変数名 IN REVERSE 1 .. 10 LOOP
繰り返し処理;
END LOOP;
|
FOR 変数名 IN REVERSE 10 .. 1 LOOP
繰り返し処理;
END LOOP;
|
EXITの記述には相違ありません。
EXIT;
EXIT [ ラベル名 ] ;
EXIT WHEN A1 > 10;
CONTINUEの記述には相違ありません。
CONTINUE;
CONTINUE [ ラベル 名 ] ;
CONTINUE WHEN 条件式;
CASEの記述には相違ありません。
CASE 変数
WHEN 条件値 THEN
分岐処理
ELSE
分岐処理
END CASE;
PostgreSQLにはGOTO命令がありません。
Oracle | PostgreSQL |
---|---|
GOTO ラベル ;
|
[対応する命令なし] |
カーソルの宣言については注意が必要です。
Oracle | PostgreSQL |
---|---|
CURSOR カーソル名 IS クエリー;
|
カーソル名 CURSOR FOR クエリー;
|
Oracle | PostgreSQL |
---|---|
CURSOR カーソル名 (引数 IN データ型) IS ...
|
カーソル名 CURSOR (引数 データ型) FOR ...
|
カーソルのFETCHの記述には相違ありません。
FETCH カーソル名 INTO 取得した値を格納する変数;
カーソルから行を1行づつ取り出して変数に格納します。
カーソルをすべてFETCHしたときの判定方法は注意が必要です。
Oracle | PostgreSQL |
---|---|
カーソル名%NOTFOUND;
|
NOT FOUND;
|
Oracleでは、カーソル名を明示して終了判定(NOTFOUND)しますが、PostgreSQLではカーソル名の指定はできません。
カーソルのカレント行に対する更新の記述には相違ありません。
<更新>
UPDATE テーブル名 SET 更新内容 WHERE CURRENT OF カーソル名;
<削除>
DELETE FROM テーブル名 WHERE CURRENT OF カーソル名;
カーソルの宣言時にFOR UPDATEを使って作成したカーソルの現在行に対して項目の値の変更およびレコードの削除を行います。
カーソルのCLOSEの記述には相違ありません。
CLOSE カーソル名;
BEGIN
CLOSE カーソル名;
EXCEPTION
WHEN invalid_cursor_name THEN NULL;
END;
CREATE OR REPLACE FUNCTION ファンクション名 ()
RETURNS refcorsor LANGUAGE plpgsql
AS $$
DECLARE
カーソル名 refcursor;
BEGIN
(中略)
RETURN カーソル名;
END;
EXCEPTIONの記述には相違ありません。
EXCEPTION
WHEN エラーコード(もしくは例外名) 1 THEN エラー処理内容1
WHEN エラーコード(もしくは例外名) 2 THEN エラー処理内容2
WHEN OTHERS THEN エラー処理内容3
END;
Oracleの例外名 | PostgreSQLの例外名 | 相違 |
---|---|---|
CASE_NOT_FOUND | CASE_NOT_FOUND | 同じ |
INVALID_CURSOR | INVALID_CURSOR_STATE | 書換え必要 |
NO_DATA_FOUND | NO_DATA_FOUND | 同じ*1 |
STORAGE_ERROR | OUT_OF_MEMORY | 書換え必要 |
TOO_MANY_ROWS | TOO_MANY_ROWS | 同じ |
ZERO_DIVIDE | DIVISION_BY_ZERO | 書換え必要 |
RAISEを使った例外を発生させる記述には相違ありません。
RAISE exception;
Oracle | PostgreSQL |
---|---|
BEGIN
EXECUTE プロシージャ名
END;
|
SELECT ファンクション名();
|
(TEXT型を返す関数を呼ぶ場合)
DECLARE
変数 TEXT;
BEGIN
変数 := ファンクション名();
PERFORM ファンクション名();
nextval('シーケンス名') -- 次の値を取り出す
setval('シーケンス名', 値) -- 値をセットする
currval('シーケンス名') -- 現在値を再度取り出す
(初期化用関数例)
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;
$$;
(登録用関数)
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 THEN
EXECUTE '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;
BEGIN
PERORM スキーマ名.初期化用ファンクション名 ();
EXECUTE 'SELECT val FROM ' || quote_ident(取得する一時テーブル名) || ' WHERE key = $1' INTO 取得した値用変数 USING 値を取得したい変数;
RETURN 取得した値用変数;
END;
$$;
版 | 所属企業・団体名 | 部署名 | 氏名 |
---|---|---|---|
ストアドプロシージャ移行調査編
第2版
(2013年度 WG2)
|
クオリカ株式会社 | 開発センター | 坂本 浩行 |
インフォメーションクリエーティブ株式会社 | ソリューション開発本部 | 林田 竜一 | |
ストアドプロシージャ移行調査編
第3版
(2017年度 WG2)
|
SRA OSS, Inc. 日本支社 | OSS 事業本部 | 佐藤 友章 |
SRA OSS, Inc. 日本支社 | OSS 事業本部 | 千田 貴大 |