2010年4月23日金曜日

SQL-Server 2008 Expressで、時間の計算を便利にしてみる(2)




前回の記事に引き続いて、SQL-Server 2008 Expressで、時間の計算を便利にしてみるの第二回目です。

前回は、"時間:分"文字列を分に換算した数値にすることによって、時間の計算を電卓感覚で便利にしてしまう(願いをこめた)関数SQLCLR_T()を作りました

今回は、そのSQLCLR_T()で得られる分に換算した数値の結果を、"時間:分"の文字列に変換する関数SQLCLR_TFormat()を作ってみます。
また、前回作ったSQLCLR_T()から、繰り返し計算回数のパラメータを取り外し、シンプルに書けるようにしてみました。

確かにまだまだオールマイティに対応できはしませんが、まず、このSQLCLR_T()と、SQLCLR_TFormat()の二つの組み合わせで、勤怠とかの計算は電卓感覚で便利に出来るかなぁと。

SQLCLRの登録などは過去の記事をご参考になさって下さい

■実行例■

--前回作ったSQL_CLR_T関数から、繰り返し計算パラメータ取り外しました!

SELECT
dbo.SQLCLR_T('01:00') +
dbo.SQLCLR_T('00:15') * 10 AS [01:00 + 00:15を10回の計算結果]

SELECT
dbo.SQLCLR_TFormat(
dbo.SQLCLR_T('01:00') +
dbo.SQLCLR_T('00:15') * 10) AS [01:00 + 00:15を10回の計算結果を時間:分文字列に変換]


■コード■
(インデントは消えております)
(無償版のVisual C# 2008でプログラムを書けます)
(全角の<と>は、半角に読み替えて下 さい)

//*******************************************************************************
// * ローカル関数
//*******************************************************************************
//------------------------------------
//TimeSpan用の日時分配列作成
//前回のSQLCLR_T()の時と同じ関数です。
//------------------------------------
private static Int32[] CreateTimeSpanSource(
Int32 p_day,
Int32 p_hour,
Int32 p_minute
)
{
//結果格納エリア
Int32[] intArr_result = new Int32[3];

try
{
//値の格納
intArr_result[0] = p_day; //日
intArr_result[1] = p_hour; //時
intArr_result[2] = p_minute; //分

//分の時間への繰上げ計算
intArr_result[1] = intArr_result[1]+
(Int32)Math.Floor((Double)intArr_result[2]/(Double)60);
//分の調整計算
intArr_result[2] = intArr_result[2] -
(Int32)Math.Floor((Double)intArr_result[2]/(Double)60)*60;
//時間の日への繰上げ計算
intArr_result[0] = intArr_result[0] +
(Int32)Math.Floor((Double)intArr_result[1] / (Double)24);
//時間の調整計算
intArr_result[1] = intArr_result[1] -
(Int32)Math.Floor((Double)intArr_result[1] / (Double)24) * 24;
}
catch (System.Exception obj_err)
{
throw obj_err;
}

return intArr_result;
}

//*******************************************************************************
//* SQL関数
//*******************************************************************************
//------------------------------------
//分に換算した数値を時間:分形式に変換する
//------------------------------------
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString SQLCLR_TFormat(
SqlInt32 p_value
)
{
//結果格納エリア
string str_result = "";
//日時分計算配列
Int32[] intArr_ts = new Int32[3];
//時間基礎エリア
TimeSpan obj_base;
try
{
//自作関数CreateTimeSpanSource()を利用して、日時分計算配列作成
intArr_ts = CreateTimeSpanSource(
0,
0,
(Int32)p_value
);
//時間基礎エリア作成
obj_base = new TimeSpan(
intArr_ts[0],
intArr_ts[1],
intArr_ts[2],
0
);
//結果エリア作成(時間:分形式)
str_result =
(obj_base.Days * 24 + obj_base.Hours).ToString() + ":" +
obj_base.Minutes.ToString("00");
}
catch (System.Exception obj_err)
{
throw obj_err;
}
return (SqlString)str_result;
}

//(前回の修正版です)
//------------------------------------
//日.時間:分文字列を分に変換する関数
//------------------------------------
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlInt32 SQLCLR_T(
SqlString p_value
)
{
//入力値作業エリア
string str_value;
//結果格納エリア
Int32 int_result = 0;
//インデックス
Int32 i;
//チェック用書式1
Regex obj_rx1 = new Regex(@"^\d{1,4}\.\d{1,4}:\d{1,4}$");
//チェック用書式2
Regex obj_rx2 = new Regex(@"^\d{1,4}:\d{1,4}$");
//チェック用書式3
Regex obj_rx3 = new Regex(@"^\d+$");
//時間基礎エリア
TimeSpan obj_base;
//時間結果エリア
char[] charArr_c = new char[2]{'.',':'};
//日時分文字列格納配列
string[] strArr_ts = new string[3];
//日時分計算配列
Int32[] intArr_ts;

try
{
str_value = (string)p_value;
//書式チェック
if (!(obj_rx1.IsMatch(str_value)))
{
if (obj_rx2.IsMatch(str_value))
{ //書式2にマッチした場合は、日要素を補完して先に進む。
str_value = "0." + str_value;
}
else if (obj_rx3.IsMatch(str_value))
{ //書式3にマッチした場合は、日.時間要素を補完して先に進む。
str_value = "0.0:" + str_value;
}
else
{ //全書式アンマッチならエラー
throw new System.Exception("書式エラー。日(最大4桁).時間(最大4桁):分(最大4桁)でお願いします。");
}
}

//入力値を日時分配列に分解して格納
strArr_ts = str_value.Split(charArr_c);
//日時分配列の内容を自作関数CreateTimeSpanSource()で調整計算し、計算配列にセット
intArr_ts = CreateTimeSpanSource(
Int32.Parse(strArr_ts[0]),
Int32.Parse(strArr_ts[1]),
Int32.Parse(strArr_ts[2])
);

//時間基礎エリアにセット
obj_base = new TimeSpan(
intArr_ts[0],
intArr_ts[1],
intArr_ts[2],
0
);

//結果を分に換算して取得
int_result = (Int32)obj_base.TotalMinutes;

}
catch (System.Exception obj_err)
{
throw obj_err;
}

return (SqlInt32)int_result;
}


■SQL-Server関数■
(環境はご自分のものに読み替えお願いいたします)

-- *******************************************************
-- SQLCLRの関数インターフェース
-- *******************************************************
-- ----------------------------------------------
-- 分の数字を"時間:分"文字列に変換する。
-- (パラメータ説明)
-- @p_value :分の数値(整数)
-- ----------------------------------------------
create function SQLCLR_TFormat(
@p_value int
)
RETURNS nvarchar(14)
AS EXTERNAL NAME ASSEMBLY_SQLCLR.CLS_SQLCLR.SQLCLR_TFormat;
GO

--前回の修正版です。
-- ----------------------------------------------
-- 時間文字列を分に換算する
-- (パラメータ説明)
-- @p_value :"日.時間:分"
-- もしくは、"時間:分。"
-- ただし、各要素は数値最大4桁
-- @p_magnification:繰り返し計算数
-- ----------------------------------------------
create function SQLCLR_T(
@p_value nvarchar(14)
)
RETURNS int
AS EXTERNAL NAME ASSEMBLY_SQLCLR.CLS_SQLCLR.SQLCLR_T;
GO