Round関数 - 数値の小数部分を丸める -Office Kitami
小数点以下を四捨五入する関数は?−0.5の加算+Int関数 - インストラクターのネタ帳
access 実践サンプル
AccessのRoundはJIS式丸めで四捨五入ではない。
負の数は処理できない。
つまり簡単に言うと
ユーザー定義関数を作らないと四捨五入できないよ
ということです。
もっと言うと
これを作らないとACCESSは使い物にならないよ
ということです。
しかしintがごちゃごちゃしてわかりません。なぜマイクロソフトは作らなかったのか。
##バージョンを上げるならはよRoundを作れ
ということはほんとうにいっておきたい。
さて、簡単に作りましょう。
なのでVBAを動くようにしておくこと、EXCELがあることが前提だと可能です。というかこういう連携こそオフィスをまとめて買う真の意味があります。
ACCESSを起動
ALT+F11でvisualBasiceditorを起動
ALT+T Alt+R で参照設定でMicrosoft Excelを参照設定する
という前提で
Function xlRnd(varLong As Long)
'For Access VBA ; You need Reference Setting Microsoft Excel XX.X Object Library
Dim xlApp As New Excel.Application: xlApp.Visible = False 'Change From Dim xlApp As Excel.Application
On Error GoTo Err
xlRnd = xlApp.WorksheetFunction.Round(varLong,1)
Set xlApp = Nothing 'Add
Exit Function
Err:
xlRnd = 0
If Not xlApp Is Nothing Then xlApp.Quit: Set xlApp = Nothing 'Add
End Function
これをクエリに入れるときにビルダを起動し
xlRnd([テーブル名]![フィールド名])
で計算できます。(式をビルドするときはクエリではなくテーブルからフィールド名をもってくること)
この参照設定は
英語では
Reference Setting
Early Binding
日本語では事前バインディングといいます。
ではもう一つレイトバインディングをやります。こちらは参照設定をしないので、違うバージョンに移行しやすいです。しかし遅いです。大量に計算させると明らかに差が出ます。
Function xlRndLate(varLong As Long)
Dim xlApp: Set xlApp = CreateObject("Excel.Application")
On Error GoTo Err
xlRnd = xlApp.WorksheetFunction.Round(varLong,1)
Set xlApp = Nothing
Exit Function
Err:
xlRnd = 0
If Not xlApp Is Nothing Then Set xlApp = Nothing
End Function
こちらは
実行時バインディングとか書いてあります
2つともエラー処理を行い、数字ではないものが入ってきた場合は0が返ります。
###おまけ Set Nothingのテクニック
If not Is nothing
はVBAではあまり使わないのですが、Set で変数を設定して放棄する場合、途中でなくなっている場合、あるいは設定できない場合があります。On errorで抜けているとわからなくなるんですね。
なのでこの
If Not 変数 Is Nothing Then Set 変数 =Nothing
とするとエラーがなく変数を放棄できます。
さらに言うと
Dim 変数:Set 変数 =
If Not 変数 Is Nothing Then Set 変数 =Nothing
は
For Next
If End IF
Do Loop
と同じように最初に書いて間にコードを書くようにしています。
Dim 変数:Set 変数 =
Dim 変数:Set 変数a =
If Not 変数a Is Nothing Then Set 変数a =Nothing
If Not 変数 Is Nothing Then Set 変数 =Nothing
こんな感じで外側から包み込むようにすると間違いが少ないです。
これはAccessの学習を始める前に、まずVBAを知っておく必要があることを意味しています。できないことはないんだけど面倒なんだもん。
ただ、簡単だけにいくら事前バインディングで早いと言ってもAccess本体で処理をするよりはやっぱり遅いです。あとユーザ定義関数だとSQLがPowerShellとかで処理できないみたい。
#Excelを使わない場合
Excelを使わないWorksheetfunction.Roundは Log10 と組み合わせたものになり、意外とややこしく、ずいぶん時間がかかりました
Static Function Log10(X) As Double
Log10 = Log(X) / Log(10#)
End Function
Function xlRnd2(X, intflo As Integer)
Dim xDegit As Integer
' IsNumeric Check
If X * 0 <> 0 Then GoTo ERR_Hndl
On Error GoTo ERR_Hndl
If intflo < 0 Then
If CInt(Log10(Abs(X))) + 1 <= Abs(intflo) Then
xlRnd2 = X 'Error Return X value
Exit Function
Else
xlRnd2 = Int((Abs(X) * 10 ^ (intflo)) + 0.5) / (10 ^ intflo) * Sgn(X)
Exit Function
End If
Else
xlRnd2 = Int((Abs(X) * 10 ^ (intflo)) + 0.5) / (10 ^ intflo) * Sgn(X)
Exit Function
End If
Exit Function
ERR_Hndl:
xlRnd2 = 0
End Function
詳しい解説はこちらで https://qiita.com/Q11Q/items/ad8e3139b02f495db181
#参考:
事前バインディングと遅延バインディング(実行時バインディング)
[INFO] オートメーションにおける事前バインディングおよび実行時バインディングの使用
[VBA references and early binding vs late binding - EXCEL MATTERS]
(http://excelmatters.com/2013/09/23/vba-references-and-early-binding-vs-late-binding/)