売上や工数、件数などのデータを扱うVBAでは、「最大値」を取る処理が頻繁に出てきます。
ところが実務では、最大値が取れたはずなのに 0になった、エラーで止まった、配列だと動かない といった事故も起こりがちです。
原因の多くは、Maxの使い方(どこに対してMaxをかけているか)と、空白・文字・未初期化の混入を想定していないことです。
この記事では、Range(セル範囲)から最大値を取る基本から、配列(1次元・2次元)で最大値を安全に取る方法までを、実務で壊れにくい設計でまとめます。
目次
- ✅ VBAで最大値を取る方法は大きく3つ
- ・3パターンの使い分け(Range / 配列 / ループ)
- ✅ Rangeの最大値を変数に取得する基本
- ・WorksheetFunction.MaxでRangeから最大値を取る
- ・エラー混入が怖いなら Application.Max を検討する
- ✅ 配列の最大値を取得する基本設計
- ・配列最大値は「走査して更新」が一番堅い
- ✅ 1次元配列の最大値を安全に取る関数
- ・関数:Variant配列から最大値を取得(数値のみ対象)
- ・呼び出し例:最大値を変数に入れて使う
- ✅ 2次元配列の最大値を取る(Range取り込み後の定番)
- ・関数:2次元配列の特定列から最大値を取得
- ・呼び出し例:Rangeを配列に読み込んで最大値(高速・安定)
- ✅ 実務でありがちな落とし穴と対策
- ・初期値を0にして最大値を更新する(NGになりやすい)
- ・型がLongで小数が落ちる
- ・Rangeにエラー値が混ざってWorksheetFunction.Maxで落ちる
- ✅ 応用:最大値だけでなく「最大の行」を取りたい
- ・関数:2次元配列で最大値と行インデックスを同時に取得
- ・呼び出し例:最大売上の担当者を取得
- ✅ Excel VBAで“集計処理”として最大値を使うときのコツ
- ✅ まとめ:VBAでMaxを安全に扱い最大値を正しく取る
✅ VBAで最大値を取る方法は大きく3つ
Maxの取り方は、目的によって最適解が変わります。
ここを曖昧にしたまま書くと、「動くけど現場データで止まる」コードになりやすいです。
特に、配列に取り込んだ後に最大値を取りたいケースでは、WorksheetFunctionに渡せず詰まる人が多いです。
また、Rangeに対してWorksheetFunction.Maxを使う場合も、空白・文字・エラー値の混入で想定外の結果になることがあります。
この章で全体像を押さえておくと、後半の実装がスムーズになります。
「RangeはRange」「配列は配列」で、Maxの取り方を切り替えるのが実務では安定します。
・3パターンの使い分け(Range / 配列 / ループ)
- Rangeの最大値:
WorksheetFunction.Max/Application.Maxが最短 - 配列の最大値:原則は ループで走査(型や空白混入に強い)
- 速度最優先:配列に読み込んで ループで最大値(Rangeを直接なめない)
✅ Rangeの最大値を変数に取得する基本
Rangeから最大値を取るのは簡単ですが、実務では「空白」「文字」「エラー値」の扱いで差が出ます。
初心者の失敗は、サンプルデータでは動くのに、現場の混ざったデータで突然止まることです。
特に WorksheetFunction.Max は、範囲にエラー値が入ると 実行時エラーになりやすく、落ち方が派手です。
また、最大値を Long に入れていたせいで小数が切り捨てられて、レポートの値がズレるケースもあります。
「数値の型」と「エラー混入時の挙動」を最初に決めておくと、後で修正が減ります。
ここでは、まず“壊れにくい基本形”を押さえます。
・WorksheetFunction.MaxでRangeから最大値を取る
操作手順(実装の流れ)
- 最大値を取りたい範囲(Range)を用意する
Doubleなど適切な型の変数を用意するWorksheetFunction.Max(範囲)を代入する- 必要なら結果を検証(空の範囲・全て空白など)
Option Explicit
Public Sub GetMaxFromRange_Basic()
Dim targetRange As Range
Dim maxValue As Double
Set targetRange = ThisWorkbook.Worksheets("Sheet1").Range("B2:B100")
' Range内の最大値を取得(Rangeにエラー値が混ざると落ちる可能性あり)
maxValue = Application.WorksheetFunction.Max(targetRange)
Debug.Print "Max=", maxValue
End Sub
なぜこの書き方か(設計意図)
- Rangeに対する最大値取得は、Excel側の関数を使うのが最短で読みやすい
Doubleにしておくと、小数・大きい値にも対応しやすい(実務データは小数が混ざりがち)
別案との違い
Longだと小数が切り捨てられやすいVariantだと型が曖昧になって、後続処理で比較が不安定になりやすい
・エラー混入が怖いなら Application.Max を検討する
Application.Max は「落ちにくい」ことがありますが、入力によっては扱いがブレるため、万能ではありません。
実務では「エラー混入の可能性があるRange」は、後述の「配列化→ループ最大」を推奨します。
Option Explicit
Public Sub GetMaxFromRange_ApplicationMax()
Dim targetRange As Range
Dim resultVariant As Variant
Set targetRange = ThisWorkbook.Worksheets("Sheet1").Range("B2:B100")
' エラーや文字混入に対して挙動が一定ではないため、要テスト
resultVariant = Application.Max(targetRange)
Debug.Print "Max=", resultVariant
End Sub
✅ 配列の最大値を取得する基本設計
ここが一番つまずきやすいポイントです。
RangeならMax関数で一発ですが、配列はそのままでは同じように扱えません。
「WorksheetFunction.Maxに配列を渡したら動くはず」と思って試して、型不一致や意図しない結果になることがよくあります。
また、配列には Empty や文字列が混ざりやすく、比較処理が崩れやすいです。
実務で壊れない形にするなら、“数値だけを対象にして最大値を更新する”というルールを明確にします。
この章の考え方を押さえると、1次元でも2次元でも同じ方針で拡張できます。
・配列最大値は「走査して更新」が一番堅い
操作手順(実装の流れ)
- 最大値の初期状態(未確定)を用意する
- 配列を先頭から走査する
- 数値だけを対象に比較する
- 大きければ最大値を更新する
- 最後に「最大値が見つかったか」を返す
✅ 1次元配列の最大値を安全に取る関数
配列最大値は、処理を関数化しておくと再利用でき、保守性が上がります。
「場当たりでFor文を書き散らかす」より、最大値取得の責務を1つに閉じ込めるのが実務向きです。
また、最大値が存在しない(全て空白/文字)場合にどうするかを決めないと、0が返って誤認する事故が起こります。
ここでは、最大値が見つからない場合に False を返す方式にします。
呼び出し側が判断できるので、誤って0を最大値と解釈しにくくなります。
“落ちない”だけでなく、“誤解しない”ことが大事です。
・関数:Variant配列から最大値を取得(数値のみ対象)
Option Explicit
Public Function TryGetMaxFrom1DArray( _
ByVal values As Variant, _
ByRef maxValue 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)
' 数値だけ対象(Empty/Null/文字を除外)
If IsNumeric(values(i)) Then
currentValue = CDbl(values(i))
If Not hasNumber Then
maxValue = currentValue
hasNumber = True
ElseIf currentValue > maxValue Then
maxValue = currentValue
End If
End If
Next i
TryGetMaxFrom1DArray = hasNumber
End Function
なぜこの書き方か(設計意図)
Try~形式にして「最大値が存在しない」を表現できる- 数値以外は無視するルールを固定し、現場データの混入に強くする
Doubleに寄せておけば整数・小数の両方を安全に扱える
別の書き方との差(メリット)
- 「初期値=0」方式は、全てマイナスのデータで壊れる(最大が-5でも0になってしまう)
WorksheetFunction.Maxに無理に渡すより、挙動が明確でテストしやすい
・呼び出し例:最大値を変数に入れて使う
Option Explicit
Public Sub Sample_MaxFrom1DArray()
Dim values(1 To 6) As Variant
Dim maxValue As Double
Dim success As Boolean
values(1) = 10
values(2) = "15"
values(3) = Empty
values(4) = 7
values(5) = "NG"
values(6) = 22.5
success = TryGetMaxFrom1DArray(values, maxValue)
If success Then
Debug.Print "Max=", maxValue
Else
Debug.Print "数値が1件もありません。"
End If
End Sub
ここでは、1次元配列を使って最大値を取得する方法を紹介しました。
配列を使った処理は、
VBAでデータ処理を行ううえで非常に重要なテクニックです。
ただし実務では、
1次元配列と2次元配列の違い
LBound / UBound の意味
配列を使ったループ処理
などを理解していないと、思わぬエラーや処理ミスにつながることもあります。
配列の基本的な仕組みや実務での使い方については、
次の記事で詳しく解説しています。
👉 【VBA】配列(Array)の基礎を徹底解説|1次元配列・2次元配列の仕組みと実務での使い方
✅ 2次元配列の最大値を取る(Range取り込み後の定番)
実務で多いのは、Rangeを配列に取り込んでから処理するパターンです。
このとき配列は2次元(行×列)になり、1次元の最大値関数はそのままでは使えません。
ここで無理に「列ごとに切り出す」などをやると、コードが散らかりやすいです。
2次元は2次元として走査し、対象列だけ比較する形にすると読みやすく保守もしやすいです。
また、Range→配列は高速化に直結するので、集計が重いブックほど効果があります。
“最大値を取る処理”を中心に、取り込みから実務形の流れで紹介します。
・関数:2次元配列の特定列から最大値を取得
Option Explicit
Public Function TryGetMaxFrom2DArrayColumn( _
ByVal values As Variant, _
ByVal targetColumnIndex As Long, _
ByRef maxValue 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
maxValue = currentValue
hasNumber = True
ElseIf currentValue > maxValue Then
maxValue = currentValue
End If
End If
Next rowIndex
TryGetMaxFrom2DArrayColumn = hasNumber
End Function
・呼び出し例:Rangeを配列に読み込んで最大値(高速・安定)
Option Explicit
Public Sub Sample_MaxFromRangeByArray()
Dim ws As Worksheet
Dim dataRange As Range
Dim dataValues As Variant
Dim maxValue As Double
Dim success As Boolean
Set ws = ThisWorkbook.Worksheets("Sheet1")
Set dataRange = ws.Range("A2:D100") ' 例:A=日付, B=担当, C=売上, D=粗利
' Rangeを一括で配列に取り込み(高速)
dataValues = dataRange.Value
' 例:C列(3列目)の最大値を取得
success = TryGetMaxFrom2DArrayColumn(dataValues, 3, maxValue)
If success Then
Debug.Print "売上最大=", maxValue
Else
Debug.Print "数値が見つかりません。"
End If
End Sub
ここでは、Rangeを配列に取り込んでから最大値を取得する方法を紹介しました。
この方法は、VBAの処理速度を改善するうえでも非常に重要なテクニックです。
特に大量データを扱う場合は、
セルを1つずつ参照するより、配列に一括で読み込んでループ処理する方が高速になります。
2次元配列の基本的な考え方や、
Rangeデータを配列に格納して処理する方法については、次の記事で詳しく解説しています。
👉 【VBA】2次元配列を使用して一括で格納・格納データをループで処理する方法
✅ 実務でありがちな落とし穴と対策
Maxは単純に見えて、事故パターンが決まっています。
しかも「たまに起きる」ので、発見が遅れて信用問題になります。
例えば、月末にだけ入る例外データ(空白や文字)が混ざって止まる、などが典型です。
また、全てマイナスのデータで初期値0方式が破綻するのもよくある事故です。
実務でのポイントは、「エラーで止まらない」だけでなく、「誤った最大値を返さない」設計です。
ここでは、現場で起きがちな落とし穴と、先ほどの関数設計でどう回避できるかを整理します。
・初期値を0にして最大値を更新する(NGになりやすい)
- 全てマイナスのとき、最大が0になってしまう
- データが空のときも0になり、成功と失敗が区別できない
→ 対策:hasNumber フラグで「最大値が存在するか」を分ける(本記事の方式)
・型がLongで小数が落ちる
- 金額は整数でも、比率・平均・単価などで小数が混ざる
Longに入れると小数が消えて、比較や表示でズレる
→ 対策:最大値は原則 Double で受ける(必要なら最後に丸める)
・Rangeにエラー値が混ざってWorksheetFunction.Maxで落ちる
#N/Aや#DIV/0!が混ざっている- “たまたま”混ざった月だけ落ちる
→ 対策:Range→配列化→数値だけ比較、の流れに寄せる
✅ 応用:最大値だけでなく「最大の行」を取りたい
実務では「最大値を取った後、その最大はどの行か?」が必要になることが多いです。
例えば、最大売上の担当者名を出したい、最大工数の案件名を出したい、などです。
ここで最大値だけ取って終わると、次の処理が二度手間になります。
最大値の更新タイミングで、行番号(インデックス)も一緒に保持すると一回の走査で済みます。
処理速度も上がり、コードの意図も明確になります。
“最大値取得”を「集計の部品」として育てるイメージです。
・関数:2次元配列で最大値と行インデックスを同時に取得
Option Explicit
Public Function TryGetMaxWithRowIndexFrom2DArray( _
ByVal values As Variant, _
ByVal targetColumnIndex As Long, _
ByRef maxValue As Double, _
ByRef maxRowIndex 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
maxValue = currentValue
maxRowIndex = rowIndex
hasNumber = True
ElseIf currentValue > maxValue Then
maxValue = currentValue
maxRowIndex = rowIndex
End If
End If
Next rowIndex
TryGetMaxWithRowIndexFrom2DArray = hasNumber
End Function
・呼び出し例:最大売上の担当者を取得
Option Explicit
Public Sub Sample_MaxValueAndOwner()
Dim ws As Worksheet
Dim dataRange As Range
Dim dataValues As Variant
Dim maxValue As Double
Dim maxRowIndex 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 = TryGetMaxWithRowIndexFrom2DArray(dataValues, 3, maxValue, maxRowIndex)
If Not success Then
Debug.Print "数値が見つかりません。"
Exit Sub
End If
ownerName = CStr(dataValues(maxRowIndex, 2))
Debug.Print "最大売上=", maxValue, "担当=", ownerName
End Sub
✅ Excel VBAで“集計処理”として最大値を使うときのコツ
Excel記事でも触れた通り、グラフや集計は「見た目」より「計算の正しさ」が土台です。
最大値取得は、集計の中では小さな部品ですが、ここが壊れると資料全体が壊れます。
特に月次レポートの自動化では、最大値がトリガーになるケース(色付け・上位抽出)が多いです。
そのため、最大値処理は“使い捨て”ではなく“再利用する部品”として設計しておくと安定します。
今回の TryGetMax~ 形式は、そのまま最小値(Min)や平均(Average)にも応用できます。
ここまで作り込むと、VBAの自動化が「動けばOK」から「壊れない運用」に変わっていきます。
✅ まとめ:VBAでMaxを安全に扱い最大値を正しく取る
- Rangeの最大値は
WorksheetFunction.Maxで手早く取れるが、エラー混入には注意 - 配列の最大値は 走査して更新が最も堅く、混在データにも強い
- 初期値0方式は事故が起きやすいので、
hasNumberで「最大値が存在するか」を分ける - 2次元配列は「対象列だけ比較」でシンプルに実装できる
- 最大値と一緒に「最大の行」も取ると、実務の集計・抽出が一気に楽になる