TL;DR —
Worksheet.Deleteは、中断して尋ねてくる 唯一のシート操作です。モーダルの確認 — デー タがあるかもしれません、と告げるあれ — を出し、無人のマクロやループの中では、そのダイアログは安全網 ではなく フリーズ です。Application.DisplayAlerts = Falseで黙らせ、エラーハンドラーで元に戻し て、クラッシュしてもセッション全体で警告が切れたままにならないようにします。ここから二つの厳しい制限 が続きます。Excel は 最後の表示シート の削除を拒み(エラー 1004)、インデックスでループしながらの 削除は、逆順 に回さない限りシートを飛ばします。
Sub DeleteSheetSafely(nm As String)
Dim ws As Worksheet
On Error GoTo Done
Application.DisplayAlerts = False
For Each ws In ThisWorkbook.Worksheets
If StrComp(ws.Name, nm, vbTextCompare) = 0 Then ws.Delete
Next ws
Done:
Application.DisplayAlerts = True ' Delete がエラーを出しても必ず戻す
End Sub
Worksheet.Delete は、タブを右クリック ▸ シートの削除 のコード版です。マクロが新しい実行の前に、作業
用シートや先月の作業タブを取り壊すのに使います。黙って仕事をこなす Add や
Copy と違い、Delete は立ち止まって人間を待ちます — そしてその一時停止こそ、
ほとんどすべてのシート削除の問題の根っこです。
この記事で学べること
- 考え方の軸 —
Deleteは取り消せず、まず尋ねてくる。そしてその質問こそがマクロをフリーズさせる - 最も大事なルール — 確認を黙らせ、それをエラーハンドラーで元に戻す
- なぜ Excel は最後の表示シートの削除を拒むのか
- なぜループの中での削除はシートを飛ばすのか、そして逆順に回すとどう直るのか
- シートが存在するときだけ削除する方法
考え方の軸:Delete はまず尋ね、そして元に戻せない
Delete についての二つの事実が、残りすべてを説明します。第一に、それは 恒久的 です — 削除されたシ
ートに元に戻す(Undo)はなく、呼び出しが成功した瞬間に、データもタブ上のすべても消えます。第二に、まさ
に恒久的だからこそ、Excel はそれを モーダルの確認ダイアログ で守ります — "Data may exist in the
sheet(s) selected for deletion. To permanently delete the data, press Delete."
最も大事なルール:確認を黙らせ、それから元に戻す
確認は Application.DisplayAlerts = False で抑制します。そして大事なのはこちらの半分です — エラーハン
ドラーで元に戻す。警告を切ったままにするのは、局所的な便宜ではありません — それは Excel セッションの残
り全体で切れたままになるグローバル設定であり、「このファイルに上書きしますか?」の確認も含めて すべて
の確認を黙らせます。警告を切ってから戻すまでのあいだにマクロが死ねば、アプリケーション全体を静かに丸腰
にしたことになります。
Sub ClearScratchSheets()
On Error GoTo Done
Application.DisplayAlerts = False
ThisWorkbook.Worksheets("Scratch").Delete
Done:
Application.DisplayAlerts = True ' エラーが出ても必ず走る
End Sub
これは、ScreenUpdating や Unprotect の周り
で使うのと同じ規律です — 切り替えたグローバルはどれも、ただ一つの出口ラベルで元に戻し、クラッシュがセッ
ションを危険な状態に残せないようにします。シートの削除について一つだけ覚えておくなら、「DisplayAlerts
はハンドラーで元に戻す」にしてください。
Excel は最後の表示シートの削除を拒む
ブックは常に少なくとも一枚の表示シートを含んでいなければならないので、最後の 表示シートに対する
Delete は実行時エラー 1004 を投げます — 警告を抑制していてもです。これは「X に一致するシートをすべて
削除する」と書いて X がたまたま全部に一致したとき、あるいは「レポート以外のすべてのシートを削除する」で
レポートが思っていた場所になかったとき、その瞬間に噛みついてきます。
削除する前に、その下限を明示的に守りましょう。
If ThisWorkbook.Worksheets.Count > 1 Then
ws.Delete
Else
MsgBox "Cannot delete the only remaining sheet."
End If
非表示 のシートは「少なくとも一枚は表示」の要件に数えられない点に注意してください。だから、表示シート 一枚と非表示シート数枚のブックでも、その表示シートの削除は拒まれます。それを消す必要があるなら、まず別 のシートを再表示してください。
なぜループの中での削除はシートを飛ばすのか
「この五枚のシートを削除する」を「二枚削除、三枚スキップ、そしてエラー」に変える罠がこれです。コレクシ
ョンを インデックスで ループし、進みながら削除すると、削除のたびに後ろのインデックスが一つずつ繰り
上がります — だから削除後の Sheets(i) は かつての Sheets(i+1) を指し、For i = 1 To Count はそれ
を素通りしていきます。
' 誤り - 削除でインデックスがずれ、シートが飛ばされる
For i = 1 To ThisWorkbook.Worksheets.Count
ThisWorkbook.Worksheets(i).Delete ' i はもう次のシートの先を指している
Next i
きれいな直し方が二つ。逆順 に回せば、ずれはすでに訪れた部分でしか起きません — 行を下から上へ削除す るのと同じ理屈です(VBA 行の削除 を参照)。
For i = ThisWorkbook.Worksheets.Count To 1 Step -1
With ThisWorkbook.Worksheets(i)
If .Name Like "Temp*" Then .Delete
End With
Next i
あるいは For Each を使います。ここでは、固定のインデックス位置ではなくオブジェクトを反復するので安全
です — TL;DR のスニペットが使っている形です。いずれにせよ、インデックスを前へ進めながら削除するのは決
してやめましょう。
ExcelMaster の活用
シートの削除は些細に見えて、四つの失敗の道を隠しています — 無人の実行をフリーズさせるモーダルの確認、
クラッシュ後に切れたまま残るグローバルな DisplayAlerts、最後の表示シートでのエラー 1004、そして狙いの
半分を飛ばす前進ループです。
ExcelMaster には、何を消したい
かを伝えられます — 「名前が Temp で始まるシートをすべて削除して、でも最後の一枚は絶対に消さないで」 —
すると、安全版を書きます。DisplayAlerts を切り、エラーハンドラーで必ず元に戻し、最後の表示シートの下
限を守るカウントガードを置き、何も飛ばさないよう逆順ループか For Each を使います。さらに、削除が恒久
的であることを念押しし、取り消せる形が欲しいときには、代わりにシートの内容を消去することを提案します。
ブックとコードはあなたの手元に残ります。
よくある質問
VBA で確認ダイアログなしにシートを削除するには?
削除の前に Application.DisplayAlerts = False を設定し、そのあと Application.DisplayAlerts = True で
元に戻します — 削除が失敗しても走るよう、理想的にはエラーハンドラーのラベルに置きます。警告を抑制すれ
ば、ThisWorkbook.Worksheets("Scratch").Delete はシートを黙って削除します。
シートを削除するときにマクロがフリーズするのはなぜ?
Delete がモーダルの確認ダイアログを出し、マクロが決して来ないクリックを待っているからです — 無人やス
ケジュール実行でよくあります。削除の前後で Application.DisplayAlerts = False を使ってダイアログを抑制
します。元に戻すのを忘れないでください。さもないと Excel セッション全体で切れたままになります。
ワークシートの削除でエラー 1004 が出るのはなぜ?
たいていは、それが最後の表示シートで、ブックは少なくとも一枚の表示シートを保たなければならないからです。
削除の前に ThisWorkbook.Worksheets.Count > 1 を確認するか、まず別のシートを再表示します。ここでのエラ
ー 1004 は確認ダイアログとは別物である点に注意してください — DisplayAlerts の抑制は、最後の一枚という
下限を取り払いません。
シートが存在するときだけ削除するには?
Exists メソッドはないので、Worksheets コレクションをループし、StrComp(ws.Name, nm, vbTextCompare) = 0
で名前を比較して、一致したら削除します。これは、直接の Worksheets("Gone").Delete がエラーを投げるのと
は違い、シートがないときは何もせずに穏やかに済ませます。
ループで複数のシートを削除するには?
インデックスで 逆順 に回すか — For i = Worksheets.Count To 1 Step -1 — For Each を使います。イン
デックスを 前へ 進めながら削除すると、後ろのインデックスがずれてシートを飛ばすからです。バッチ全体で
DisplayAlerts を抑制し、最後の削除が 1004 を投げないよう、最後の表示シートのカウントを守りましょう。
検証環境
検証環境: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-09-14。
関連ガイド: VBA シートの追加 · VBA シートのコピー · VBA DisplayAlerts · VBA 行の削除 · VBA エラー処理
