集合を返す関数 generate_series

PostgreSQLには、8.0 から集合を返す関数というのがある。
8.0 時点では、generate_series が唯一みたいだけど。

generate_series( start, stop )
generate_series( start, stop, step )

startからstopまでの連番を1(またはstep)刻みで生成します。
step には負の値を指定することも可能です。

select * from generate_series( 1, 5 );
generate_series
---------------------
1
2
3
4
5

今回はこの generate_series を7.4の時代に使いたくて自作したので、そのことについて書いてみる。
まず、generate_series の使いどころ。

PostgreSQLのマニュアルにも書かれているけど、任意の日付の何日おきの日付を取得するとか。
自分の場合は、generate_series で月の初日(1)から月の最後(8月なら31)までの日付を生成し、
テーブルに格納されているデータを join する。
データがない日は日付だけでそれ以外はNULLな行になった日付と関連付いたデータを取得できる。

例えば、以下のような schedule テーブルがあったとする。

sdate      schedule
-----------------------
2007-08-01 買い物
2007-08-03 休み
2007-08-04 買い物

で、SQL文とその結果。

select day,schedule 
    from ( select * generate_series(1,5) as day ) base 
        left outer join (select * from schedule) t1 
            on base.day=extract(day from t1.sdate) 
                order by base.day;

day  schedule
----------------------------
1      買い物
2
3      休み
4      買い物
5

まぁ連番があれば、他にもいろいろと便利なことは多い。
で、自作したわけです。
旧 PostgreSQL 以外にも、MySQL とか Oracle とかでも使えるとおもう。
ただし、PostgreSQL でしか確認していないので、他の環境では保証できないです。

CREATE FUNCTION generate_series_mine(integer, integer) RETURNS SETOF integer
    AS '
DECLARE
    maxcnt ALIAS FOR $2 ;
    cnt integer ;
BEGIN
    cnt := $1 ;
    WHILE cnt <= maxcnt LOOP
        RETURN NEXT cnt ;
        cnt := cnt + 1 ;
    END LOOP;
    RETURN ;
END;
'
    LANGUAGE plpgsql;

8.0 にバージョンアップしたときに、組み込み関数とバッティングしないように、generate_series_mine という関数名にしています。

まぁたいしたことはやってないので、見ればわかるんじゃないかと。
もし見ている方で解説欲しい方がいればコメントいただければ解説します。

なお、組み込み関数と同じ状態にするには、引数と戻り値、内部で使う cnt の定義を bigint にしたものも定義しないといけない。
また、それぞれに第三の引数を設定し、10行目を
cnt := cnt + 第三引数 ;
にしたものも定義しないといけないです。

参考文献
『PostgreSQL 8.0.0 文書 9.18. 集合を返す関数』

カテゴリ:

関連する記事

この記事に関連する記事は、0 件です。

トラックバック

このブログ記事に対するトラックバックURL
http://fakelife.info/mt/system/mt-tb.cgi/22

コメントする


画像の中に見える文字を入力してください。