[pgsql-jp: 39077] Re: 複数テーブルからの検索結果を、複数行列返す関数

NASUNO Isao isao.nasuno @ ctc-g.co.jp
2008年 1月 26日 (土) 09:42:06 JST


いたがきさま、KEN公さま

那須野です。

根本的なことを理解しないまま関数を使っていましたが、すこし理解が進んだように思います。
次回は、同じ轍を踏まなくてよさそうです。
大変参考になりました。

ありがとうございました。


chuuken kenkou wrote:
> 忠犬KEN公です。
> 
> 質問のやり取りをざくっと眺めただけなので、ポイントを外した意見かも
> 知れませんが。。。
> 
> ストアド・ファンクションとストアド・プロシジャの違いが、PostgreSQLでは
> 分かりにくいために混同しているように感じます。
> 
> 標準SQLや主要なRDBMSでは、ストアド・ファンクションはcreate
>  function、ストアド・プロシジャはcreate procedureで定義します。
> ストアド・ファンクションは、その名の通り関数であり、一回の呼び出しで
> 返却する値は、1個です。
> それに対して、ストアド・プロシジャは、複数行の処理が可能です。
> 
> ストアド・ファンクションは、「select 関数名(引数) from 表名 〜」と
> いった呼び出し方をし、ストアド・プロシジャは、「call プロシジャ名(引数)」
> といった呼び出し方をします。
> 
> PostgreSQLでは、ストアド・ファンクション、ストアド・プロシジャの明確な
> 区別がなく、create functionで定義し、select文で呼び出す形になって
> います。
> 
> select ストアド・ファンクション名(引数) from 〜
> という指定は、関数としての使い方になるため、1回の関数呼び出しでは
> 1個の値を返却するように関数を定義しておく必要があります。
> 「(列値1、列値2)」のように返却されたのは、値をrecord(行)形式で返却
> するように関数が定義されているためです。
> 
> ストアド・ファンクション中で、PL/pgSQLの手続文が書けないといったことは
> ありません。返却値を1個にするように定義すれば、関数として動作させら
> れます。
> 
> 
>> Date: Fri, 25 Jan 2008 17:55:44 +0900
>> From: itagaki.takahiro @ oss.ntt.co.jp
>> To: pgsql-jp @ ml.postgresql.jp
>> Subject: [pgsql-jp: 39072] Re: 複数テーブルからの検索結果を、複数行列返す関数
>>
>>
>> NASUNO Isao  wrote:
>>
>>> これからも関数を作る場面が出てきそうなのですが、
>>> PL/pgSQL と SQL の違いが、私にはよく飲み込めません。
>>>
>>> PL/pgSQL=SQL手続き言語というのは、LOOPやFORなどを使って、
>>> 手続き式にSQLを処理するような記述をしたものでしょうか。
>>>
>>> 今回、FOR、LOOP、IN EXECUTE などを使った例も参考にしたのですが(難しくて挫折した)、
>>> これらには、教えていただいた方法は使えないということでしょうか?
>> 例示された testfunc() ならばシンプルなので、SQL のみで実現できると思います。
>> もし、testfunc() でもっと複雑なことをしようと思うと、SQL だけでは足りず、
>> フロー制御などがある手続き言語 (PL/pgSQL など) を使うことになると思います。
>>
>> しかし、ストアド関数に SQL 以外の言語を使った場合、今回の書き方では
>> エラーになるようです。エラーを避けるには、「複数テーブルからの検索結果を
>> マージするストアド関数」も自作する必要がありそうです。
>> (二重のFORループで実現できそうですが、効率が悪い場合も若干あります。)
>>
>> SQL 関数の場合はそのまま処理できる理由は、関数のインライン化が効き、
>> 単純な JOIN にまでクエリを変形できているからだと思われます。
>>
>>
>> -- PL/pgSQL で同じ機能を実現(ただしエラーになる)
>> CREATE FUNCTION testfunc2(integer,
>> OUT id integer,
>> OUT key text)
>> RETURNS SETOF record AS
>> $$
>> DECLARE
>> r record;
>> BEGIN
>> FOR id, key IN SELECT
>> header.id, target.name||' '||target.descript
>> FROM
>> header,
>> target
>> WHERE
>> header.id=$1 and header.targetid=target.id
>> LOOP
>> RETURN NEXT;
>> END LOOP;
>> END;
>> $$ LANGUAGE plpgsql;
>>
> 
> _________________________________________________________________
> 「ペットの悩み、みんなにきいたら解決した。」安心のペットライフにMSN相談箱
> http://questionbox.msn.co.jp/c531.html


/那須野



pgsql-jp メーリングリストの案内