Excelでデータを扱う際、「フィルターで抽出した結果だけを処理したい」「非表示データを除外して値を取得したい」という場面は多いものです。
しかし、VBAで通常の範囲指定を行うと、フィルターで非表示になっている行も含まれてしまうため、意図しない計算や集計ミスにつながることがあります。
このような問題を解決するためには、「フィルター後の値(=可視セルのみ)」を取得する方法を理解しておくことが重要です。
この記事では、SpecialCells(xlCellTypeVisible)
を活用し、オートフィルタで抽出されたデータのみをVBAで安全に取得・処理する方法を詳しく紹介します。
目次
- ✅ フィルター後の値を取得する必要性
- ・通常のRange指定では非表示行も含まれる
- ✅ フィルター後の可視セルだけを取得する基本構文
- ・基本コード
- ✅ コード解説:動作の仕組みを理解しよう
- ・1. AutoFilter.Range で範囲を動的取得
- ・2. .Offset(1, 0) でヘッダー行を除外
- ・3. .SpecialCells(xlCellTypeVisible) で可視セルを抽出
- ・4. On Error Resume Next で安全にエラー回避
- ✅ 可視セルから値を配列として取得する
- ・配列に格納して高速処理
- ✅ 応用例①:フィルタ後の合計値を求める
- ✅ 応用例②:フィルタ後の値を別シートに転記
- ✅ 注意点とエラー対策
- ・1. 可視セルがない場合にエラーが発生する
- ・2. フィルタが設定されていない場合
- ・3. 複数範囲(Areas)が生成されるケース
- ✅ 実務での活用:集計・チェック・転記を自動化
- ✅ まとめ:VBAでフィルター後の値を正確に取得しよう
✅ フィルター後の値を取得する必要性
・通常のRange指定では非表示行も含まれる
たとえば以下のようなデータをフィルタで「営業部」のみ表示している場合を考えてみましょう。
部門 | 氏名 | 売上 |
---|---|---|
営業部 | 田中 | 200 |
開発部 | 佐藤 | 150 |
営業部 | 山田 | 300 |
開発部 | 鈴木 | 180 |
この状態で次のようなVBAを実行すると…
MsgBox WorksheetFunction.Sum(Range("C2:C5"))
結果は 「830」(全行)になります。
見た目では「営業部」だけ表示されていますが、VBAは非表示の「開発部」データも含めて計算してしまうのです。
そこで使うのが、可視セルのみを対象とする「SpecialCells」です。
参考:【VBA】条件に一致するセルを取得する方法|Find・For Each・SpecialCells
✅ フィルター後の可視セルだけを取得する基本構文
・基本コード
Sub GetFilteredValues()
Dim ws As Worksheet
Dim rng As Range
Dim visibleCells As Range
Dim cell As Range
Dim result As String
' シート設定
Set ws = ThisWorkbook.Sheets("データ")
' オートフィルタが設定されていなければ終了
If ws.AutoFilterMode = False Then
MsgBox "オートフィルタが設定されていません。", vbExclamation
Exit Sub
End If
' フィルタ範囲を取得
Set rng = ws.AutoFilter.Range
' 可視セル(フィルタ後の値)を取得(ヘッダー除外)
On Error Resume Next
Set visibleCells = rng.Offset(1, 0).Resize(rng.Rows.Count - 1).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
' 可視セルの値を取得
If Not visibleCells Is Nothing Then
For Each cell In visibleCells.Columns(3).Cells ' 3列目(売上列)を指定
result = result & cell.Value & vbCrLf
Next cell
MsgBox "フィルター後の売上値:" & vbCrLf & result, vbInformation
Else
MsgBox "該当データがありません。", vbExclamation
End If
End Sub
このコードでは、
- オートフィルタ範囲を特定
- 表示されている(可視)セルだけを抽出
参考:【VBA】オートフィルタ後の可視セルを取得する方法|抽出データだけを扱う実務テクニック - 指定列の値を順番に読み取る
という手順で、フィルタ後の値を取得しています。
✅ コード解説:動作の仕組みを理解しよう
・1. AutoFilter.Range で範囲を動的取得
表全体のフィルタ設定範囲を自動的に特定します。
固定範囲を手動で指定するよりも柔軟に対応でき、どの列でフィルタしても機能します。
参考:【VBA】フィルタを使って空白行を削除する方法|効率的にデータを整理しよう
・2. .Offset(1, 0) でヘッダー行を除外
フィルタ範囲にはヘッダーも含まれるため、1行下から対象範囲を指定します。
この指定がないとヘッダー行も処理に含まれてしまいます。
参考:【Excel】OFFSET関数の使い方をわかりやすく解説|基礎から応用まで
・3. .SpecialCells(xlCellTypeVisible) で可視セルを抽出
これがポイントです。
非表示になっている行(フィルタ除外データ)は自動的に除外され、画面上に見えているセルだけが取得されます。
参考:【VBA】特定のセル(空白セル・数式セル・エラーセル)を見つけ出す:SpecialCells メソッド
・4. On Error Resume Next で安全にエラー回避
フィルタ結果が0件の場合、SpecialCells
はエラーを返すため、エラー制御を入れておくことで中断を防ぎます。
参考:【VBA】On Error Resume Nextでエラーを無視してエラーの制御
✅ 可視セルから値を配列として取得する
・配列に格納して高速処理
多くの行データを扱う場合、1セルずつループするより配列に格納する方が高速です。
次のコードは、フィルタ後の値を配列に格納して処理する例です。
Sub GetFilteredValuesArray()
Dim ws As Worksheet
Dim visibleCells As Range
Dim arr As Variant
Dim i As Long
Set ws = ThisWorkbook.Sheets("データ")
' フィルタ範囲から可視セルを取得
On Error Resume Next
Set visibleCells = ws.AutoFilter.Range.Offset(1, 0).Resize(ws.AutoFilter.Range.Rows.Count - 1).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If visibleCells Is Nothing Then
MsgBox "該当データがありません。", vbExclamation
Exit Sub
End If
' 可視セルの3列目(売上)を配列に格納
arr = visibleCells.Columns(3).Value
' 出力確認
For i = 1 To UBound(arr, 1)
Debug.Print arr(i, 1)
Next i
End Sub
この方法を使えば、抽出されたデータを一括で処理できます。
集計や他シート転記など、実務でも効率的に応用可能です。
✅ 応用例①:フィルタ後の合計値を求める
フィルタ後のデータだけを対象に合計を出すには、WorksheetFunction.Sum
と可視セルを組み合わせます。
Sub SumVisibleValues()
Dim ws As Worksheet
Dim visibleCells As Range
Dim total As Double
Set ws = ThisWorkbook.Sheets("データ")
On Error Resume Next
Set visibleCells = ws.Range("C2:C100").SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If Not visibleCells Is Nothing Then
total = WorksheetFunction.Sum(visibleCells)
MsgBox "フィルター後の合計値:" & total, vbInformation
Else
MsgBox "集計対象が見つかりません。", vbExclamation
End If
End Sub
このコードを実行すると、フィルタで表示されている行の合計値のみが計算されます。
非表示行は無視されるため、誤集計を完全に防げます。
参考:【Excel】自動計算による足し算を行う方法|SUM関数・オートSUM・テーブルの活用まで解説
✅ 応用例②:フィルタ後の値を別シートに転記
レポート作成などで、フィルタ後の結果だけを別シートに出力したい場合もあります。
Sub CopyFilteredValues()
Dim ws As Worksheet
Dim visibleCells As Range
Set ws = ThisWorkbook.Sheets("データ")
On Error Resume Next
Set visibleCells = ws.AutoFilter.Range.Offset(1, 0).Resize(ws.AutoFilter.Range.Rows.Count - 1).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If Not visibleCells Is Nothing Then
visibleCells.Copy Destination:=ThisWorkbook.Sheets("抽出結果").Range("A1")
MsgBox "フィルター後のデータを転記しました。", vbInformation
Else
MsgBox "抽出結果がありません。", vbExclamation
End If
End Sub
このマクロでは、オートフィルタ後の表示行だけを一括コピーして「抽出結果」シートに貼り付けます。
報告資料の作成や、データ加工の中間ステップとして非常に便利です。
参考:【VBA】VLOOKUP を別シートで使う方法と実用例
✅ 注意点とエラー対策
・1. 可視セルがない場合にエラーが発生する
SpecialCells
は対象がないと「実行時エラー1004」を返します。
必ず On Error Resume Next
で制御しましょう。
・2. フィルタが設定されていない場合
AutoFilter.Range
はフィルタ未設定時に存在しないため、
If ws.AutoFilterMode = False Then
で事前確認が必要です。
・3. 複数範囲(Areas)が生成されるケース
抽出結果が途切れた場合、visibleCells
は複数範囲(Areas)に分かれます。
その場合は次のようにループして処理します。
Dim area As Range
For Each area In visibleCells.Areas
Debug.Print area.Address
Next area
✅ 実務での活用:集計・チェック・転記を自動化
実務では次のようなシーンで「フィルタ後の値取得」が役立ちます。
- 「特定条件で抽出したデータだけを別シートにまとめる」
- 「フィルタで抽出された営業担当者の売上を合計する」
- 「未処理タスクだけをリストアップして別表に転記する」
これらの作業をVBAで自動化すれば、毎日の報告やデータ整理がわずか数秒で完了します。
また、非表示データを誤って処理しないため、業務の正確性も高まります。
✅ まとめ:VBAでフィルター後の値を正確に取得しよう
SpecialCells(xlCellTypeVisible)
で可視セル(フィルタ後の値)を取得できる- 通常の範囲指定では非表示行も含まれるため誤処理の原因になる
On Error Resume Next
とAutoFilterMode
チェックで安全に動作- 合計・転記・配列処理など、応用範囲が非常に広い
- レポート作成やデータ抽出の自動化に最適
フィルタ後の値を正確に取得できれば、Excelの操作を「目で見る作業」から「ロジックで制御する作業」に変えられます。
業務の再現性とスピードが劇的に向上しますので、ぜひこの方法を日常業務に取り入れてみてください。