postgreSQL その31 トリガ、ルール、スキーマのつづき
postgreSQL その8 課題リストは2018/4/30時点でのオイラの所見
[P.253]
■関数
【概要】
PostgreSQLでは、データベースに関数を定義することができる。
一般的にはストアドプロシージャと呼ばれている。 ストアドプロシージャでは、DBMSに備わっている便利な関数や機能を利用できるので、アプリケーションが出の複雑な処理をDBMS側に任せることができる。 また、大量のデータをアプリケーション側へ渡されずにデータベースで処理できるので、ネットワークの負荷軽減などにも有用。
【おいらの考え】
RDBMS側の関数(ストアドプロシージャ)を使うと、もしデータを他のDBMSに移行する際の可搬性が損なわれる。パフォーマンスに影響が小さいなら、アプリケーション側の機能を使う方が可搬性は高くなる。
【言語の登録】
PostgreSQLでは、関数の記述にいくつかの言語を使用することができる。
デフォルトでは、SQLと、PostgreSQL特有の手続き型言語であるPL/pgSQLが使用できる。
PL/pgSQLでは、SQLで記述できないループや条件分岐などの複雑な処理を定義することができる。
その他、PL/PerlやPL/Pythonといった言語もサポートしている(それらの言語を使用する場合はcreatelangで登録する)
【関数の定義】
[書式]
create [or replace] function 関数名(引数) returns [setof] 戻り値 as $$
関数の記述
$$ language 使用言語;
or replaceを付与すると、既存の同名関数を上書きする。「戻り値」には、integerやtextなどのデータ型を指定できるほか、特定のテーブル名を指定することで、そのテーブルの行と同じデータを戻り値とすることができる。
複数の戻り値を取る場合には、setofを付与する。
「使用言語」には、関数を記述する言語を指定する。
「引数」の表現方法はいくつかある。代表的なものは、引数となるデータ型を記述するか、変数名とデータ型のセットを記述する。前者は、引数を関数内部において$nで利用し、後者は、引数を関数内部において変数名で利用する。
次の例は、簡単なSQLで記述した関数。
[例]
testdb=> select * from tb1;
col1 | col2
------+------
1 | 1
2 | 2
3 | 3
(3 rows)
testdb=> create function add_func(int,int) returns bigint as $$
select ($1 + $2)::bigint /* 引数2つを足す*/
$$ language sql;
CREATE FUNCTION
testdb=> create function insert_func(int, text) returns setof tb1 as $$
select * from tb1 where col1 = $1 and col2 = $2
$$ language sql;
CREATE FUNCTION
【関数の構造】
ここでは、PL/pgSQLで記述する関数の構造を解説する。関数の構造は基本的に次の形となる。
[書式]
declare
変数の宣言
begin
関数の処理記述
end;
DECLAREの部分には、関数内部で使用する変数の宣言を記述する。
変数の宣言は次のような書式となる。
[書式]
変数名 [constant] データ型 [not null] [ {deault | := } 値など ];
DEFAULTによりデフォルト値を指定しない場合、変数の初期値はNULLとなる。
CONSTANTを付与すると、その変数への値の代入は禁止される。
変数へ値を代入する際には「 := 」という書式を使う。
次にしますのは、変数宣言の例。
[例]
・integer型でデフォルト値を10賭した変数var_1の宣言
var_1 int default 10;
・text型でSampleを固定値とした変数var_2の宣言
var_2 constant text := 'Sample';
関数の処理記述では、変数を利用したSQLやループ処理、条件分岐などを定義できる。
コメントは「 - コメント 」あるいは、「/* コメント */ 」の形式を受け付ける。
ループ処理では、loop、exit、continue、while、forといった文を、
条件分岐では、if、case文をそれぞれ使用できる。
ループ処理や条件分岐は、ネストにすることも可能。
次に、簡単な関数の記述例を示す。
[例]
testdb=> create or replace function test_func(int, timestamp) returns integer as
testdb-> $$
testdb$> declare
testdb$> r timestamp; -- LOOPで使用する変数の宣言
testdb$> result int := 0; -- 戻り値に使用する変数の宣言
testdb$> begin
testdb$> for r in select c2 from tb1 where c1 = $1 -- FOR文でc2の値を逐次r屁代入
testdb$> loop
testdb$> if r < $2 -- 第二引数のtimestampの情報より古い日付かチェック
testdb$> then
testdb$> result := result + 1; -- IFの結果が真ならresultをインクリメント
testdb$> end if; -- IFの終了
testdb$> end loop; -- LOOPの終了
testdb$> return result; -- 戻り値を返す
testdb$> end
testdb$> $$
testdb-> language plpgsql;
CREATE FUNCTION