Excel VBAでフィルター処理を行ったあと、
「表示されている行だけをFor Nextで処理したい」
「抽出されたデータに対してループ処理をしたい」
と考えたことはありませんか。
一見すると、
For i = 2 To lastRow
' 処理
Next i
のような通常のループで問題なさそうに見えますが、
フィルターがかかった状態では、この考え方がそのまま通用しません。
実務では、
- フィルターしているのに非表示行まで処理してしまう
- 処理件数が合わない
- 可視セルだけ処理したつもりがエラーになる
といったトラブルが非常に多く発生します。
この記事では、
「VBA × フィルター × For Next」という
実務で必ず直面するテーマを、
- なぜ失敗するのか
- 正しい処理パターンは何か
- 実務で安全な書き方はどれか
という視点で、徹底的に解説します。
目次
- ✅ フィルター後のFor Nextが危険と言われる理由
- ・実務で起きがちな失敗例
- ✅ フィルターがかかった状態でのRangeとRowsの挙動を理解する
- ・フィルターの正体
- ・これがトラブルの根本原因
- ✅ 基本パターン①:フィルター後にFor Nextで全行を処理するケース
- ・このパターンが成立する場面
- ・基本コード例
- ・注意点
- ✅ 基本パターン②:可視セルのみをFor Nextで処理する考え方
- ・重要な考え方
- ✅ パターン①:SpecialCells(xlCellTypeVisible) を使う方法
- ・可視セルだけ取得するコード
- ・この方法のメリット
- ・注意点(重要)
- ・実務向けの安全な書き方
- ✅ パターン②:For NextでRowsを逆順に処理する方法
- ・NG例(順方向)
- ・正解例(逆順ループ)
- ・なぜ逆順が安全なのか
- ✅ パターン③:ListObject(テーブル)+For Next の考え方
- ・テーブルの可視行だけ処理する例
- ・ListObjectを使うメリット
- ✅ フィルター解除 → For Next の順序は超重要
- ・基本構成(推奨)
- ・なぜ順序が重要なのか
- ✅ フィルター × For Next × 集計処理の実務例
- ・可視セルのみ合計する例
- ・COUNTやSUMをFor Nextで行う意義
- ✅ フィルター × For Next × 転記処理の実務例
- ✅ UiPath・RPAと組み合わせるときの注意点
- ・おすすめ設計
- ✅ よくある失敗まとめ
- ✅ まとめ:VBA フィルター For Next は「考え方」が9割
✅ フィルター後のFor Nextが危険と言われる理由
フィルター後のFor Next処理は、
VBA初心者〜中級者が必ず一度は失敗するポイントです。
なぜなら、Excelの「見た目」とVBAの「処理対象」は
必ずしも一致しないからです。
・実務で起きがちな失敗例
- 画面上は10行しか見えていないのに、100行分処理される
- 抽出データだけ集計したつもりが、全件が対象になる
- 行削除でインデックスがズレて処理漏れが出る
これらはすべて、
フィルター状態を考慮せずにFor Nextを使ったことが原因です。
✅ フィルターがかかった状態でのRangeとRowsの挙動を理解する
まず前提として、
フィルターは「行を削除」しているわけではありません。
・フィルターの正体
- 行は存在している
- ただし「非表示」になっている
- VBAからは通常の行として認識される
つまり、
For i = 2 To lastRow
と書いた時点で、
非表示行も含めてループされるということです。
・これがトラブルの根本原因
- 見えていない行まで処理される
- 「抽出したつもり」が成立しない
👉 フィルター後の処理では、
可視セルだけを対象にする工夫が必須です。
✅ 基本パターン①:フィルター後にFor Nextで全行を処理するケース
まず、「あえて全行を処理する」ケースです。
・このパターンが成立する場面
- フィルターは表示用
- 実際の処理対象は全件
- 見た目は関係ない
この場合、通常のFor Nextで問題ありません。
・基本コード例
Dim i As Long
Dim lastRow As Long
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To lastRow
' 全行を処理
Next i
・注意点
この書き方は、
「フィルター結果だけ処理したい」場合には使えません。
✅ 基本パターン②:可視セルのみをFor Nextで処理する考え方
ここからが本題です。
フィルター後に
「表示されている行だけを処理したい」
場合、考え方を変える必要があります。
・重要な考え方
- 行番号でループしない
- 可視セルの集合を作る
- その集合をFor Each / For Nextで処理する
✅ パターン①:SpecialCells(xlCellTypeVisible) を使う方法
最も代表的で、
実務でもよく使われる方法です。
・可視セルだけ取得するコード
Dim rng As Range
Dim cell As Range
Set rng = Range("A2:A" & lastRow).SpecialCells(xlCellTypeVisible)
For Each cell In rng
' 可視セルのみ処理
Next cell
・この方法のメリット
- フィルター結果どおりに処理できる
- 行削除・集計・転記に使いやすい
・注意点(重要)
可視セルが 1件もない場合、
SpecialCells は エラーになります。
・実務向けの安全な書き方
Dim rng As Range
On Error Resume Next
Set rng = Range("A2:A" & lastRow).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If rng Is Nothing Then Exit Sub
このガードは、
実務では必須レベルです。
参考:【VBA】条件に一致するセルを複数取得する方法|Find・For Each・SpecialCells
✅ パターン②:For NextでRowsを逆順に処理する方法
行削除を伴う処理では、
For Nextの回し方そのものに注意が必要です。
・NG例(順方向)
For i = 2 To lastRow
If Rows(i).Hidden = False Then
Rows(i).Delete
End If
Next i
このコードは、
行削除によるズレが発生します。
・正解例(逆順ループ)
For i = lastRow To 2 Step -1
If Rows(i).Hidden = False Then
Rows(i).Delete
End If
Next i
・なぜ逆順が安全なのか
- 削除しても未処理行の番号が変わらない
- 処理漏れが起きない
👉 フィルター × 行削除 × For Next
では 逆順が鉄則です。
参考:【VBA】重複削除で“最新データだけ残す”方法|複数条件にも対応できる実務最強テクニック
✅ パターン③:ListObject(テーブル)+For Next の考え方
データがテーブル化されている場合、
Rangeベースの考え方は捨てた方が安全です。
・テーブルの可視行だけ処理する例
Dim tbl As ListObject
Dim i As Long
Set tbl = Worksheets("データ").ListObjects("tblData")
For i = 1 To tbl.DataBodyRange.Rows.Count
If tbl.DataBodyRange.Rows(i).Hidden = False Then
' 可視行のみ処理
End If
Next i
・ListObjectを使うメリット
- フィルター状態の判定が正確
- 列追加に強い
- RPA連携でも安定
参考:【VBA】テーブル作成を自動化するListObjects.Addメソッド完全ガイド
✅ フィルター解除 → For Next の順序は超重要
実務では、
- フィルター解除を忘れる
- 途中で解除してしまう
といったミスも頻発します。
・基本構成(推奨)
With Worksheets("データ")
If .FilterMode Then .ShowAllData
' フィルター設定
.Range("A1").AutoFilter Field:=2, Criteria1:="東京"
' For Next 処理
End With
・なぜ順序が重要なのか
- 前回実行状態の影響を受けない
- 再実行しても結果が安定する
✅ フィルター × For Next × 集計処理の実務例
・可視セルのみ合計する例
Dim total As Double
Dim cell As Range
For Each cell In Range("C2:C" & lastRow).SpecialCells(xlCellTypeVisible)
total = total + cell.Value
Next cell
・COUNTやSUMをFor Nextで行う意義
- 条件分岐を細かく書ける
- 複雑な業務ロジックに対応できる
✅ フィルター × For Next × 転記処理の実務例
Dim src As Range
Dim destRow As Long
destRow = 2
For Each src In Range("A2:A" & lastRow).SpecialCells(xlCellTypeVisible)
Cells(destRow, 10).Value = src.Value
destRow = destRow + 1
Next src
✅ UiPath・RPAと組み合わせるときの注意点
RPAからExcelを操作する場合、
フィルター × For Next の考え方を誤ると、
- 取得件数が合わない
- 可視行しか取れない/逆に全件取れる
といった事故が起きます。
・おすすめ設計
- VBAでフィルターとFor Next処理を完結させる
- RPAは結果だけを扱う
これにより、
ロボット側の不安定要素が激減します。
✅ よくある失敗まとめ
- フィルター後も通常のFor Nextを使う
- 可視セル0件時のエラー未対策
- 行削除で順方向ループ
- フィルター解除忘れ
✅ まとめ:VBA フィルター For Next は「考え方」が9割
- フィルターは非表示にするだけ
- For Nextは見た目を考慮しない
- 可視セルを明示的に扱う必要がある
- SpecialCellsと逆順ループが実務の要
- テーブル(ListObject)は最も安定する
VBA フィルター × For Next は、
一度正しく理解すれば、
抽出・集計・転記処理の幅が一気に広がります。
ぜひ、
「なぜ今までズレていたのか」
を意識しながら、コードを見直してみてください。