スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

PL/pgSQLで文字列で時間を作成する(改訂版)

PL/pgSQLで文字列で時間を作成するで作った時間を作る関数で、色々と問題があったので改訂版を作ることにしました。
最大の問題は、入力される時間のチェックが甘いこと。例えば、分は0から59までの範囲に入っているかチェックするした方が良いかなと、思いました。
また、全体的に関数の名前がぶつからないように、uv_をつけることにしました。
■文字列が設定されているか判定する

CREATE OR REPLACE FUNCTION uv_is_set(
p_src text@
) RETURNS boolean AS $$
DECLARE
BEGIN
RETURN p_src IS NOT NULL AND '' <> p_src;
END;
$$ LANGUAGE plpgsql;

■文字列が数値か判定する

CREATE OR REPLACE FUNCTION uv_is_number(
p_src text
,p_min bigint DEFAULT -9223372036854775808
,p_max bigint DEFAULT 9223372036854775807
) RETURNS boolean AS $$
DECLARE
w_value bigint;
BEGIN
IF NOT uv_is_set(p_src) THEN
RETURN FALSE;
END IF;
BEGIN
w_value := p_src::bigint;
IF p_min <= w_value AND w_value <= p_max THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
EXCEPTION
WHEN invalid_text_representation THEN
RETURN FALSE;
END;
END;
$$ LANGUAGE plpgsql;

数値をチェックする関数に引数として最大値と最小値を追加しました。
この範囲を超えるとfalseが返ってきます。
デフォルト値付きなので、引数を与えなければbigintの範囲内ならtrueを返すようになっています。
整数だけ有効にしたい場合は最小値だけ0を入れればOKです。
さて、後は時間を作成する関数となるわけですが、その前にもう一つ問題を解決します。
実は以前の時間作成関数ではマイクロ秒がうまく扱えませんでした。
例えば、マイクロ秒として'9'を与えると'00:00:00.9'になっていました。本当は'00:00:00.000009'になってほしかったのです。
さらに、'90'でも'900'でも'00:00:00.9'になってしまうのです。
うまく設定するには'000009'を引数に与える必要があります。
ということで、0埋めをする関数を作りました。
■整数の文字埋め

CREATE OR REPLACE FUNCTION uv_padding_integer(
p_value bigint
,p_keta int
,p_padding text
) RETURNS text AS $$
DECLARE
w_result text := '';
BEGIN
IF p_value IS NULL
OR p_value < 0
OR p_keta IS NULL
OR p_keta < 1
OR NOT uv_is_set(p_padding)
OR 1 < char_length(p_padding)
THEN
RETURN NULL;
END IF;
w_result := p_value::text;
FOR i IN 1..p_keta - char_length(w_result) LOOP
w_result := p_padding || w_result;
END LOOP;
RETURN w_result;
END;
$$ LANGUAGE plpgsql;

文字埋めしたい数値と、桁数と、埋めたい文字が引数になります。数値はマイナスの扱いがよくわからなかったので、整数のみ有効にしています。
最後に改訂版の時間作成関数です。
■文字列から時間を作る

CREATE OR REPLACE FUNCTION uv_make_time(
p_year text DEFAULT '0001'
,p_month text DEFAULT '01'
,p_day text DEFAULT '01'
,p_hour text DEFAULT '00'
,p_minute text DEFAULT '00'
,p_second text DEFAULT '00'
,p_micro text DEFAULT '000000'
) RETURNS timestamp with time zone AS $$
DECLARE
w_micro text;
BEGIN
IF uv_is_number(p_year, -4713, 294276)
AND uv_is_number(p_month, 1, 12)
AND uv_is_number(p_day, 1, 31)
AND uv_is_number(p_hour, 0, 23)
AND uv_is_number(p_minute, 0, 59)
AND uv_is_number(p_second, 0, 59)
AND uv_is_number(p_micro, 0, 999999)
THEN
w_micro := uv_padding_integer(p_micro::bigint, 6, '0');
RETURN p_year || '-' || p_month || '-' || p_day || ' ' || p_hour || ':' || p_minute || ':' || p_second || '.' || w_micro;
ELSE
RETURN NULL;
END IF;
END;
$$ LANGUAGE plpgsql;

以前との違いは数値のチェックで有効範囲をいれていることと、マイクロ秒の文字埋めです。
年の有効範囲はPostgreSQLのマニュアルにある年の最大値と最小値からとりました。

追記 2009/09/26 10:28
マイクロ秒をミリ秒と勘違いしていたので、修正
スポンサーサイト

COMMENTS

COMMENT FORM

TRACKBACK


この記事にトラックバックする(FC2ブログユーザー)

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。