VBAで自動化 VBA一覧 フィルター結果の取得・判定 抽出・検索処理

【VBA】オートフィルタの対象がない場合に何もしないようにする方法|安全な自動処理の基本

Excelでオートフィルタを使ったVBAを組むとき、よくあるトラブルのひとつが「対象データが存在しないときのエラー」です。
例えば、条件で抽出した結果が1件も該当しない場合、SpecialCells(xlCellTypeVisible).Delete を実行するとエラーが発生してしまいます。

このような事態を防ぐには、「オートフィルタの対象がない場合は何もしない」 という安全な条件分岐を組み込む必要があります。
この記事では、エラーを出さずにVBAを安定稼働させるための定番テクニックを、実務で使える形で詳しく解説します。

✅ よくある問題:「対象がない」ときに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 で条件分岐

該当データがない場合、visibleRangeNothing のままになります。
この状態を利用して「何もしない(Exit Sub)」で安全に処理を終了します。

参考:【VBA】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 NextIf visibleRange Is Nothing の組み合わせで安全に判定
  • 事前に AutoFilterMode を確認しておくとより安定
  • 「スキップ」「ログ出力」「共通関数化」などで再利用性を高める
  • 実務では「落ちないVBA」を書くことが何より重要

VBAの自動処理は「正常時だけ動くマクロ」では意味がありません。
データが0件でも、シート構造が変わっても、安全に動作して止まらない仕組みこそが、信頼されるVBAスクリプトの条件です。
ぜひ今回の方法を取り入れて、安定した自動化環境を実現してください。

-VBAで自動化, VBA一覧, フィルター結果の取得・判定, 抽出・検索処理