売上・在庫・工数・納期など、実務データを扱っていると「最小値」を取りたい場面はかなり多いです。
一方で、最小値は最大値より事故が起きやすく、0になってしまう、マイナスが混ざると崩れる、配列だと取れないといったトラブルがよく起きます。
原因はだいたい決まっていて、初期値の置き方と、空白・文字・エラー値を想定しない設計です。
この記事では、Range(セル範囲)から最小値を取る基本から、配列(1次元・2次元)で最小値を安全に取る方法まで、実務で壊れにくい形でまとめます。
目次
- ✅ VBAで最小値を取る方法は大きく3つ
- ・3パターンの使い分け(Range / 配列 / 高速化)
- ✅ Rangeの最小値を変数に取得する基本
- ・WorksheetFunction.MinでRangeから最小値を取る
- ・エラー混入が怖いなら Application.Min も候補(ただし万能ではない)
- ✅ 配列の最小値を取得する基本設計
- ・配列最小値は「走査して更新」が一番堅い
- ✅ 1次元配列の最小値を安全に取る関数
- ・関数:Variant配列から最小値を取得(数値のみ対象)
- ・呼び出し例:最小値を変数に入れて使う
- ✅ 2次元配列の最小値を取る(Range取り込み後の定番)
- ・関数:2次元配列の特定列から最小値を取得
- ・呼び出し例:Rangeを配列に読み込んで最小値(高速・安定)
- ✅ 実務でありがちな落とし穴と対策
- ・初期値を0にして最小値を更新する(ほぼNG)
- ・型がLongで小数が落ちる
- ・Rangeにエラー値が混ざってWorksheetFunction.Minで落ちる
- ✅ 応用:最小値だけでなく「最小の行」を取りたい
- ・関数:2次元配列で最小値と行インデックスを同時に取得
- ・呼び出し例:最小売上の担当者を取得
- ✅ 最小値は「異常検知」や「下限チェック」に使える
- ✅ まとめ:VBAでMinを安全に扱い最小値を正しく取る
✅ VBAで最小値を取る方法は大きく3つ
最小値の取り方は、データの置き場所(Rangeか配列か)で変えるのが安全です。
ここを曖昧にすると「手元のサンプルでは動くけど、現場データで止まる」になりがちです。
特に配列は、WorksheetFunctionにそのまま渡せない/渡せても型や混在データで挙動が怪しくなります。
また、Rangeに対してWorksheetFunction.Minを使う場合でも、エラー値混入で落ちることがあります。
この章で全体像を押さえると、後半の設計意図が腑に落ちます。
結論として、RangeはMin関数、配列は走査(ループ)が実務では安定します。
・3パターンの使い分け(Range / 配列 / 高速化)
- Rangeの最小値:
WorksheetFunction.Min/Application.Min - 配列の最小値:原則は ループで走査(混在データに強い)
- 大量データ:Rangeを配列に読み込んで ループで最小値(高速)
✅ Rangeの最小値を変数に取得する基本
Rangeから最小値を取るのは一見簡単ですが、実務では「空白」「文字」「エラー値」「0の意味」が絡むと判断ミスが起きます。
初心者がよくやる失敗は、Minが取れたからOKと思ってしまい、実は空白や文字を含んだ範囲で結果が歪むケースです。
また WorksheetFunction.Min は、範囲に #N/A などが混ざると実行時エラーになり、処理が止まります。
さらに、最小値を Long に入れて小数が切り捨てられ、帳票の値がズレる事故もあります。
ここでは「壊れにくい基本形」を押さえた上で、落とし穴と対策も示します。
・WorksheetFunction.MinでRangeから最小値を取る
操作手順(実装の流れ)
- 最小値を取りたい範囲(Range)を用意する
- 受け取る変数は基本
Doubleにする WorksheetFunction.Min(範囲)を代入する- エラー混入があり得るなら設計を切り替える(後述)
Option Explicit
Public Sub GetMinFromRange_Basic()
Dim targetRange As Range
Dim minValue As Double
Set targetRange = ThisWorkbook.Worksheets("Sheet1").Range("B2:B100")
' Range内の最小値を取得(エラー値が混ざると落ちる可能性あり)
minValue = Application.WorksheetFunction.Min(targetRange)
Debug.Print "Min=", minValue
End Sub
なぜこの書き方か(設計意図)
- Rangeが対象ならExcel関数を使うのが短くて読みやすい
Doubleにすることで小数や大きな数値でも安定しやすい
別案との違い
Longは小数が落ち、比較が崩れる原因になるVariantは後続の比較処理で型がブレやすい
・エラー混入が怖いなら Application.Min も候補(ただし万能ではない)
Application.Min は落ちにくいことがありますが、入力の混在状況によって結果が読みづらくなることもあるため、「エラー混入の可能性があるRange」は配列化→ループの方が堅いです。
Option Explicit
Public Sub GetMinFromRange_ApplicationMin()
Dim targetRange As Range
Dim resultVariant As Variant
Set targetRange = ThisWorkbook.Worksheets("Sheet1").Range("B2:B100")
resultVariant = Application.Min(targetRange)
Debug.Print "Min=", resultVariant
End Sub
✅ 配列の最小値を取得する基本設計
ここがつまずきポイントです。
RangeならMin関数で一発でも、配列はそのまま同じ発想で扱えません。
さらに配列は Empty、文字列、Nullのような“混ざり”が起きやすく、比較の前提が崩れます。
実務で壊れない形にするには、「数値だけを対象に最小値を更新する」というルールを固定します。
また「最小値が存在しない(全部空白や文字)」ケースを、0やFalseで誤魔化すと誤認の原因になります。
ここでは Try~ 形式で、見つかったかどうかを返す設計にします。
・配列最小値は「走査して更新」が一番堅い
操作手順(実装の流れ)
- 最小値の初期状態(未確定)を用意する
- 配列を先頭から走査する
- 数値だけを対象に比較する
- 小さければ最小値を更新する
- 最後に「最小値が見つかったか」を返す
✅ 1次元配列の最小値を安全に取る関数
最小値取得は関数化しておくと、Min/Maxやしきい値判定に流用できます。
場当たりのFor文は増えやすく、後から仕様変更(例:文字は除外、0は除外、負数は除外など)が入った瞬間に崩れます。
ここでは「数値だけ対象」「最小値が存在しない場合はFalse」を基本にします。
これにより、空データでも誤って0を最小値と認識しにくくなります。
“落ちない”だけでなく、“誤解しない”ことが重要です。
・関数:Variant配列から最小値を取得(数値のみ対象)
Option Explicit
Public Function TryGetMinFrom1DArray( _
ByVal values As Variant, _
ByRef minValue As Double _
) As Boolean
Dim i As Long
Dim hasNumber As Boolean
Dim currentValue As Double
If Not IsArray(values) Then Exit Function
hasNumber = False
For i = LBound(values) To UBound(values)
If IsNumeric(values(i)) Then
currentValue = CDbl(values(i))
If Not hasNumber Then
minValue = currentValue
hasNumber = True
ElseIf currentValue < minValue Then
minValue = currentValue
End If
End If
Next i
TryGetMinFrom1DArray = hasNumber
End Function
なぜこの書き方か(設計意図)
Try~にして、最小値が存在しないケースを表現できる- 数値以外を除外して、混在データでも壊れにくくする
Doubleに寄せて小数・負数を含む実務データに対応する
別の書き方との差(メリット)
- 初期値を0にすると、最小値が正しく取れない(例えば全て正の値でも0が最小になってしまう)
WorksheetFunction.Minに無理に渡すより挙動が明確でテストしやすい
・呼び出し例:最小値を変数に入れて使う
Option Explicit
Public Sub Sample_MinFrom1DArray()
Dim values(1 To 6) As Variant
Dim minValue As Double
Dim success As Boolean
values(1) = 10
values(2) = "15"
values(3) = Empty
values(4) = -3
values(5) = "NG"
values(6) = 22.5
success = TryGetMinFrom1DArray(values, minValue)
If success Then
Debug.Print "Min=", minValue
Else
Debug.Print "数値が1件もありません。"
End If
End Sub
✅ 2次元配列の最小値を取る(Range取り込み後の定番)
実務で多いのは、Rangeを配列に取り込んで処理するパターンです。
このとき配列は2次元(行×列)になり、1次元のMin関数はそのまま使えません。
ここで列ごとに切り出すような実装にすると、コードが散らかりがちです。
2次元は2次元として走査し、対象列だけ比較する形にすると読みやすく保守もしやすいです。
また、Range→配列化は高速化に直結するため、データが増えるほど効果が出ます。
ここでは、取り込みから最小値取得までを“定番形”としてまとめます。
・関数:2次元配列の特定列から最小値を取得
Option Explicit
Public Function TryGetMinFrom2DArrayColumn( _
ByVal values As Variant, _
ByVal targetColumnIndex As Long, _
ByRef minValue As Double _
) As Boolean
Dim rowIndex As Long
Dim hasNumber As Boolean
Dim currentValue As Double
If Not IsArray(values) Then Exit Function
hasNumber = False
For rowIndex = LBound(values, 1) To UBound(values, 1)
If IsNumeric(values(rowIndex, targetColumnIndex)) Then
currentValue = CDbl(values(rowIndex, targetColumnIndex))
If Not hasNumber Then
minValue = currentValue
hasNumber = True
ElseIf currentValue < minValue Then
minValue = currentValue
End If
End If
Next rowIndex
TryGetMinFrom2DArrayColumn = hasNumber
End Function
・呼び出し例:Rangeを配列に読み込んで最小値(高速・安定)
Option Explicit
Public Sub Sample_MinFromRangeByArray()
Dim ws As Worksheet
Dim dataRange As Range
Dim dataValues As Variant
Dim minValue As Double
Dim success As Boolean
Set ws = ThisWorkbook.Worksheets("Sheet1")
Set dataRange = ws.Range("A2:D100") ' 例:A=日付, B=担当, C=売上, D=粗利
dataValues = dataRange.Value
' 例:C列(3列目)の最小値を取得
success = TryGetMinFrom2DArrayColumn(dataValues, 3, minValue)
If success Then
Debug.Print "売上最小=", minValue
Else
Debug.Print "数値が見つかりません。"
End If
End Sub
ここでは、Rangeを配列に取り込んでから
2次元配列の最小値を取得する方法を紹介しました。
同じ考え方で、最大値を取得する処理も実装できます。
売上の最高値や最大工数など、実務では最大値を取得する場面も非常に多くあります。
変数・配列の両方に対応した最大値の取得方法については、
次の記事で詳しく解説しています。
👉 【VBA】Max関数で最大値を取得する方法|変数・配列対応
✅ 実務でありがちな落とし穴と対策
MinはMaxより「初期値の置き方」が難しいです。
雑に書くと、最小値が0に固定されたり、空データで誤判定したりします。
また、0が“有効な値”なのか“欠損の代替”なのかで判断が変わります。
このような曖昧さを残すと、月末や例外データで事故になります。
ここでは、現場でよくある落とし穴と対策を整理します。
・初期値を0にして最小値を更新する(ほぼNG)
- 正のデータしかない場合、最小値が0になりやすい
- データが空でも0になり、成功と失敗を区別できない
→ 対策:hasNumber フラグで「最小値が存在するか」を分ける(本記事の方式)
・型がLongで小数が落ちる
- 単価・比率・平均などで小数が混ざる
Longに入れて丸められ、比較がズレる
→ 対策:最小値は基本 Double、必要なら最後に丸める
・Rangeにエラー値が混ざってWorksheetFunction.Minで落ちる
#N/Aや#DIV/0!が混ざる- 特定の月や特定部署だけで止まる
→ 対策:Range→配列化→数値だけ比較、の流れに寄せる
実務では、最小値を取得したときに
0が最小値として取得されてしまうケースも少なくありません。
例えば
空白セルを0として扱ってしまう
初期値の設定によって0が最小値になる
実際には0を除外して最小値を取りたい
といったケースです。
このように0を除外して最小値を取得する方法については、
次の記事で詳しく解説しています。
✅ 応用:最小値だけでなく「最小の行」を取りたい
実務では、最小値を取った後に「その行の担当者」や「案件名」を取りたいことが多いです。
例えば、最小売上の担当のフォローが必要、最小在庫の商品を発注したい、などです。
この場合、最小値だけ取って終わると、また検索し直すことになります。
最小値の更新と同時に行インデックスも保持しておけば、1回の走査で完結します。
処理が速くなり、コードも読みやすくなります。
・関数:2次元配列で最小値と行インデックスを同時に取得
Option Explicit
Public Function TryGetMinWithRowIndexFrom2DArray( _
ByVal values As Variant, _
ByVal targetColumnIndex As Long, _
ByRef minValue As Double, _
ByRef minRowIndex As Long _
) As Boolean
Dim rowIndex As Long
Dim hasNumber As Boolean
Dim currentValue As Double
If Not IsArray(values) Then Exit Function
hasNumber = False
For rowIndex = LBound(values, 1) To UBound(values, 1)
If IsNumeric(values(rowIndex, targetColumnIndex)) Then
currentValue = CDbl(values(rowIndex, targetColumnIndex))
If Not hasNumber Then
minValue = currentValue
minRowIndex = rowIndex
hasNumber = True
ElseIf currentValue < minValue Then
minValue = currentValue
minRowIndex = rowIndex
End If
End If
Next rowIndex
TryGetMinWithRowIndexFrom2DArray = hasNumber
End Function
・呼び出し例:最小売上の担当者を取得
Option Explicit
Public Sub Sample_MinValueAndOwner()
Dim ws As Worksheet
Dim dataRange As Range
Dim dataValues As Variant
Dim minValue As Double
Dim minRowIndex As Long
Dim success As Boolean
Dim ownerName As String
Set ws = ThisWorkbook.Worksheets("Sheet1")
Set dataRange = ws.Range("A2:D100") ' B列=担当, C列=売上想定
dataValues = dataRange.Value
success = TryGetMinWithRowIndexFrom2DArray(dataValues, 3, minValue, minRowIndex)
If Not success Then
Debug.Print "数値が見つかりません。"
Exit Sub
End If
ownerName = CStr(dataValues(minRowIndex, 2))
Debug.Print "最小売上=", minValue, "担当=", ownerName
End Sub
✅ 最小値は「異常検知」や「下限チェック」に使える
最小値は、最大値よりも「異常検知」に向いています。
例えば、工数が0になっている、在庫がマイナスになっている、単価が極端に低い、などです。
こうした異常は、平均や合計では埋もれがちです。
最小値を取る処理が安定していると、チェック自動化が一段進みます。
今回の TryGetMin~ 形式は、そのまま「0を除外する最小値」や「負数だけの最小値」などへ拡張できます。
“動く”だけでなく“運用できる”形にしておくと、後から効いてきます。
✅ まとめ:VBAでMinを安全に扱い最小値を正しく取る
- Rangeの最小値は
WorksheetFunction.Minが手早いが、エラー混入には注意 - 配列の最小値は 走査して更新が最も堅く、混在データに強い
- 初期値0方式は誤判定が多いので、
hasNumberで「存在」を分ける - 2次元配列は「対象列だけ比較」でシンプルに実装できる
- 最小値と一緒に「最小の行」も取ると、実務の抽出やフォローが一気に楽になる
最小値取得は、集計だけでなく 異常検知・チェック自動化にも直結する基礎部品です。
Maxとセットで設計しておくと、比較カテゴリの一連の処理が“壊れない部品”として揃っていきます。