2012/02/07

PostgreSQL の interval (と reltime)

PostgreSQL にて n ヶ月後の初日や最終日を文字列で返す関数を登録しようとした。
イメージとしてはこんな感じ。
create or replace function first_date_string_on_month(integer)
returns varchar
as 
$BODY$select to_char(date_trunc('month', current_date + interval '$1 months'), 'YYYY/MM/DD')$BODY$
language 'sql';
だがこれだとうまくいかなくて、引数に何を与えても 2012/03/01 が返ってくる。
'$1 months' が '1 months' とみなされている気がする。

で、次にやってみたのがこんな感じ。
create or replace function first_date_string_on_month(integer)
returns varchar
as 
$BODY$select to_char(date_trunc('month', current_date + interval ($1 || ' months')), 'YYYY/MM/DD')$BODY$
language 'sql';
構文エラーで登録すらできない。

interval だとだめなのかなと思って、interval のいらない current_timestamp で挑戦してみる。
create or replace function first_date_string_on_month(integer)
returns varchar
as 
$BODY$select to_char(date_trunc('month', current_timestamp + ($1 || ' months')), 'YYYY/MM/DD')$BODY$
language 'sql';
「ERROR: 演算子が存在しません: date + text」と言われる。

なるほど text だからキャストが必要なのかと言うことで varchar にキャストしてみる。
create or replace function first_date_string_on_month(integer)
returns varchar
as 
$BODY$select to_char(date_trunc('month', current_timestamp + cast($1 || ' months' as varchar)), 'YYYY/MM/DD')$BODY$
language 'sql';
これまた演算子が存在しないと言われる。

そういや、そもそも interval ってなんなんだ
と思って調べてみるとどうやらデータ型らしい。
interval '1 months' みたいに書くから識別子とかかと思ってたらデータ型でキャストというか型変換を意味していたのか!
というわけでこうしてみた。
create or replace function first_date_string_on_month(integer)
returns varchar
as 
$BODY$select to_char(date_trunc('month', current_timestamp + cast($1 || ' months' as interval)), 'YYYY/MM/DD')$BODY$
language 'sql';
登録できたよ。
select first_date_string_on_month(3)
--  → 2012/05/01
select first_date_string_on_month(-2)
--  → 2011/12/01
select first_date_string_on_month(0)
--  → 2012/02/01
ちゃんと動いてるよ。

ちなみに reltime というデータ型もあるみたい。
create or replace function first_date_string_on_month(integer)
returns varchar
as 
$BODY$select to_char(date_trunc('month', current_timestamp + cast($1 || ' months' as reltime)), 'YYYY/MM/DD')$BODY$
language 'sql';
とすると登録できて同じ結果が取得できた。
reltime型 を引数に取る interval 関数というのがあるので、それが関係していると思われるがよくわからない。
Google 先生で調べても PostgreSQL と realtime の検索結果が表示されるし。
とりあえず interval を使うのが正当だと思うのでそれでいいや。