Excelでオートフィルタを使ったVBAを組むとき、よくあるトラブルのひとつが「対象データが存在しないときのエラー」です。
例えば、条件で抽出した結果が1件も該当しない場合、SpecialCells(xlCellTypeVisible)
や .Delete
を実行するとエラーが発生してしまいます。
このような事態を防ぐには、「オートフィルタの対象がない場合は何もしない」 という安全な条件分岐を組み込む必要があります。
この記事では、エラーを出さずにVBAを安定稼働させるための定番テクニックを、実務で使える形で詳しく解説します。
目次
- ✅ よくある問題:「対象がない」ときにVBAが止まる
- ・フィルタ結果が0件になるとエラー1004が発生
- ✅ エラーを回避して「対象がない場合は何もしない」基本構文
- ・最も基本的な対策例
- ✅ コード解説:エラーを出さないための仕組み
- ・1. On Error Resume Next の使い方
- ・2. If visibleRange Is Nothing で条件分岐
- ・3. 処理完了後にフィルタを解除
- ✅ 応用:フィルタ条件を動的に設定しても安全に動作させる
- ✅ 応用②:該当がない場合に「ログだけ残す」
- ✅ 可視セルがない場合に落ちない「汎用関数」を作る
- ✅ 注意点と実務でのコツ
- ・AutoFilterMode と FilterMode の違いを理解する
- ・On Error Resume Next の使いすぎに注意
- ・複数条件や複数列フィルタも同様に安全化できる
- ✅ まとめ:対象がないときは「何もしない」で安全に終わらせる
✅ よくある問題:「対象がない」ときにVBAが止まる
・フィルタ結果が0件になるとエラー1004が発生
次のようなコードを見たことがある人も多いでしょう。
Sub DeleteFilteredRows()
Range("A1").AutoFilter Field:=1, Criteria1:="完了"
Range("A1").CurrentRegion.Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
End Sub
このマクロは「A列が『完了』の行を削除する」処理です。
しかし、もし該当データが1件もない場合、SpecialCells(xlCellTypeVisible)
が対象を見つけられず、次のようなエラーが発生します。
参考:【VBA】条件に一致するセルを取得する方法|Find・For Each・SpecialCells
実行時エラー '1004': 指定された種類のセルは見つかりません。
つまり、フィルタ結果が空の場合に備えて何もせず安全に終了する処理を追加しなければ、日常運用では簡単に停止してしまうのです。
参考:【VBA】RangeクラスのSelectメソッドが失敗しました:1004
✅ エラーを回避して「対象がない場合は何もしない」基本構文
・最も基本的な対策例
以下のコードでは、フィルタ後に可視セルが存在しない場合はスキップするようにしています。
Sub SafeDeleteFilteredRows()
Dim ws As Worksheet
Dim rng As Range
Dim visibleRange As Range
Set ws = ThisWorkbook.Sheets("データ")
' A列で「完了」を抽出
ws.Range("A1").AutoFilter Field:=1, Criteria1:="完了"
' フィルタ範囲を取得
Set rng = ws.AutoFilter.Range
' 可視セルを取得(ヘッダー除外)
On Error Resume Next
Set visibleRange = rng.Offset(1, 0).Resize(rng.Rows.Count - 1).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
' 該当セルがない場合は何もしない
If visibleRange Is Nothing Then
MsgBox "該当データがないため、処理をスキップしました。", vbInformation
ws.AutoFilterMode = False
Exit Sub
End If
' 行を削除
visibleRange.EntireRow.Delete
ws.AutoFilterMode = False
MsgBox "完了データを削除しました。", vbInformation
End Sub
参考:【VBA】If ElseIf Elseを使って「何もしない」条件分岐を実装する方法
参考:【VBA】IF文で何もしない処理しない(continueステートメント)
参考:【VBA】Select Case文で「何もしない」条件
✅ コード解説:エラーを出さないための仕組み
・1. On Error Resume Next の使い方
SpecialCells(xlCellTypeVisible)
は該当セルがないときにエラーを返します。
そのため、一時的にエラーを無視し(Resume Next)、すぐ後で If visibleRange Is Nothing Then
で判定するのが鉄則です。
参考:【VBA】On Error Resume Nextでエラーを無視してエラーの制御
・2. If visibleRange Is Nothing で条件分岐
該当データがない場合、visibleRange
は Nothing
のままになります。
この状態を利用して「何もしない(Exit Sub)」で安全に処理を終了します。
・3. 処理完了後にフィルタを解除
ws.AutoFilterMode = False
でフィルタ状態をリセットします。
解除しないままだと、次の処理が意図通りに動かない場合があるため、明示的に解除しておくのが実務の基本です。
参考:【VBA】フィルター後の値を取得する方法|可視セルから安全にデータを読み取る
✅ 応用:フィルタ条件を動的に設定しても安全に動作させる
実務では、毎回同じ条件ではなく、変数やセルの値を条件にフィルタをかけたい場面も多いでしょう。
そのようなケースでも、上記の「Nothingチェック」を入れておけば安全に動作します。
Sub DynamicFilterAndDelete()
Dim ws As Worksheet
Dim filterValue As String
Dim visibleRange As Range
Set ws = ThisWorkbook.Sheets("データ")
' 条件をセルから取得
filterValue = ws.Range("E1").Value
' 条件でフィルタ
ws.Range("A1").AutoFilter Field:=1, Criteria1:=filterValue
On Error Resume Next
Set visibleRange = ws.AutoFilter.Range.Offset(1, 0).Resize(ws.AutoFilter.Range.Rows.Count - 1).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
' 対象がなければ終了
If visibleRange Is Nothing Then
MsgBox "条件「" & filterValue & "」に該当するデータはありません。", vbInformation
ws.AutoFilterMode = False
Exit Sub
End If
visibleRange.EntireRow.Delete
ws.AutoFilterMode = False
MsgBox "条件「" & filterValue & "」のデータを削除しました。", vbInformation
End Sub
このようにすれば、ユーザーが指定した条件に応じて自動削除でき、
対象がない場合もスムーズにスキップできるため、実務の自動処理に非常に向いています。
参考:【VBA】Findの戻り値を理解する方法|Nothing判定と実務での活用例を解説
✅ 応用②:該当がない場合に「ログだけ残す」
対象がなかったときに「何もしない」だけでなく、「処理結果を記録しておく」方法も有効です。
たとえば管理用シートやログファイルに記録しておけば、後から原因を追いやすくなります。
Sub LogWhenNoData()
Dim ws As Worksheet
Dim visibleRange As Range
Dim logWs As Worksheet
Dim lastRow As Long
Set ws = ThisWorkbook.Sheets("データ")
Set logWs = ThisWorkbook.Sheets("ログ")
ws.Range("A1").AutoFilter Field:=2, Criteria1:="未完了"
On Error Resume Next
Set visibleRange = ws.AutoFilter.Range.Offset(1, 0).Resize(ws.AutoFilter.Range.Rows.Count - 1).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
' ログに出力
If visibleRange Is Nothing Then
lastRow = logWs.Cells(Rows.Count, "A").End(xlUp).Row + 1
logWs.Range("A" & lastRow).Value = "未完了データなし:" & Format(Now, "yyyy/mm/dd hh:nn:ss")
ws.AutoFilterMode = False
Exit Sub
End If
' 通常処理(削除など)
visibleRange.EntireRow.Delete
ws.AutoFilterMode = False
End Sub
このようにログを残す仕組みを入れておくと、業務の自動化でも安心して運用できます。
✅ 可視セルがない場合に落ちない「汎用関数」を作る
同じようなエラーチェックを毎回書くのが面倒な場合は、
「安全に可視セルを取得する関数」として共通化しておくのもおすすめです。
Function GetVisibleRange(ByVal targetRange As Range) As Range
On Error Resume Next
Set GetVisibleRange = targetRange.SpecialCells(xlCellTypeVisible)
On Error GoTo 0
End Function
この関数を使えば、どんな処理でも安全に可視セルを取得できます。
Sub ExampleUse()
Dim rng As Range
Set rng = GetVisibleRange(Range("A2:A10"))
If rng Is Nothing Then
MsgBox "可視セルがありません。"
Else
rng.Interior.Color = RGB(255, 255, 150)
End If
End Sub
このように関数化しておくことで、どのマクロでも「対象がない場合は何もしない」を簡単に実現できます。
✅ 注意点と実務でのコツ
・AutoFilterMode と FilterMode の違いを理解する
AutoFilterMode
:オートフィルタの機能がONかどうかFilterMode
:実際にフィルタでデータが絞り込まれているかどうか
どちらも組み合わせてチェックすると、より堅牢になります。
If ws.FilterMode = False Then
MsgBox "現在フィルタは適用されていません。"
End If
・On Error Resume Next の使いすぎに注意
全体を無視するのではなく、必要な部分だけで使い、直後に解除する(On Error GoTo 0)ことが重要です。
これを怠ると、本来のエラーまで見逃してしまいます。
・複数条件や複数列フィルタも同様に安全化できる
複雑な条件を設定しても、最終的に visibleRange Is Nothing
をチェックすれば同じ考え方で安全に処理を終えられます。
参考:【VBA】AutoFilterの複数条件を設定する方法|AND・ORを自在に操る実務向け活用術
✅ まとめ:対象がないときは「何もしない」で安全に終わらせる
SpecialCells(xlCellTypeVisible)
は対象がないときにエラーを返すOn Error Resume Next
→If visibleRange Is Nothing
の組み合わせで安全に判定- 事前に
AutoFilterMode
を確認しておくとより安定 - 「スキップ」「ログ出力」「共通関数化」などで再利用性を高める
- 実務では「落ちないVBA」を書くことが何より重要
VBAの自動処理は「正常時だけ動くマクロ」では意味がありません。
データが0件でも、シート構造が変わっても、安全に動作して止まらない仕組みこそが、信頼されるVBAスクリプトの条件です。
ぜひ今回の方法を取り入れて、安定した自動化環境を実現してください。