Excelで月別・支店別・担当者別など複数シートに同じ処理を手作業で繰り返していないでしょうか。シートが5枚・10枚・20枚と増えるほど作業時間も比例して増え、コピペミスやシートの抜け漏れも発生しやすくなります。VBAマクロのループ処理を使えば、何枚シートがあっても1回の実行で一括処理が完了します。本記事では、複数シートをループ処理する2種類の基本構文から始まり、実務でよく使うパターン別のサンプルコードまで、コピペしてすぐ使える形で徹底解説します。
複数シートのループ処理に使う2つの構文
VBAで複数シートをループ処理する方法は主に2種類あります。「For Each〜Next」と「For〜Next(インデックス番号指定)」です。どちらを使うべきかは処理内容によって異なりますので、それぞれの特徴を理解したうえで使い分けましょう。
' ===================================
' 方法1:For Each〜Next(推奨・シンプル)
' ===================================
Sub ForEachサンプル()
Dim ws As Worksheet ' ワークシート型の変数を宣言
For Each ws In ThisWorkbook.Worksheets ' ブック内の全シートを順番に処理
' ここに各シートへの処理を書く
ws.Range("A1").Value = ws.Name ' 各シートのA1にそのシート名を入力
Next ws
End Sub
' ===================================
' 方法2:For〜Next(インデックス番号指定)
' ===================================
Sub ForNextサンプル()
Dim i As Long ' カウンター変数を宣言
For i = 1 To ThisWorkbook.Worksheets.Count ' シート1枚目から最後まで
' ここに各シートへの処理を書く
Worksheets(i).Range("A1").Value = i ' 各シートのA1にシート番号を入力
Next i
End Sub
For Each〜Nextの特徴:シートを変数(ws)に直接入れて操作するためコードがシンプルになります。すべてのシートを同じ処理で一括操作する場合に最も使いやすい構文です。
For〜Next(インデックス番号)の特徴:シートを番号で管理するため「2枚目から最後まで」「偶数番目のシートだけ」など、柔軟な範囲指定ができます。処理するシートを絞り込む場合に便利です。
絶対に覚えるべき重要ポイント:シートを明示的に指定する
For Each〜Nextでシートをループする際に初心者が最も多く陥る落とし穴が、「処理対象のシートを明示的に指定し忘れる」ことです。変数wsにシートを格納していても、Range等の操作でwsを付け忘れると、アクティブシート(現在表示しているシート)に対してしか処理が行われません。
' ============================
' 誤った書き方(よくある間違い)
' ============================
Sub 間違いサンプル()
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
Range("A1").Value = "処理済み" ' ← wsを付け忘れている!
' アクティブシートのA1にしか書き込まれない(全シートに適用されない)
Next ws
End Sub
' ============================
' 正しい書き方
' ============================
Sub 正しいサンプル()
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
ws.Range("A1").Value = "処理済み" ' ← ws.を付けて対象シートを明示する
' ループするたびに各シートのA1に書き込まれる(正常動作)
Next ws
End Sub
ループ内でセル・行・列・セル範囲などを操作する際は、必ず変数名(ws.)を頭に付けることを徹底してください。これを守るだけで大半のシートループのトラブルを防ぐことができます。
実務で使えるサンプルコード集
パターン1:全シートの特定セルに同じ値を一括入力する
ヘッダーの更新・タイトルの変更・日付の一括更新など、すべてのシートの同じセルに同じ値を入力したい場合に使います。最もシンプルなループ処理のパターンです。
' ============================
' 全シートのA1に「2025年度」を入力する
' ============================
Sub 全シート一括入力()
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
ws.Range("A1").Value = "2025年度"
Next ws
MsgBox "全シートへの入力が完了しました。"
End Sub
' ============================
' 全シートの特定行(1行目)をまとめて書式設定する
' ============================
Sub 全シートヘッダー書式設定()
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
With ws.Rows(1)
.Font.Bold = True ' 太字
.Interior.Color = RGB(0, 112, 192) ' 背景色(青)
.Font.Color = RGB(255, 255, 255) ' 文字色(白)
End With
Next ws
MsgBox "全シートのヘッダー書式設定が完了しました。"
End Sub
パターン2:特定のシートを除外してループする
「目次シート」「集計シート」「テンプレートシート」など、処理対象から外したいシートがある場合は、If文でシート名を判定して除外します。実務では最もよく使うパターンのひとつです。
' ============================
' 「集計」シートと「目次」シートを除外してループする
' ============================
Sub 特定シート除外ループ()
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
' シート名が「集計」または「目次」の場合はスキップ
If ws.Name = "集計" Or ws.Name = "目次" Then
GoTo Continue
End If
' ↑以下が処理対象シートへの処理
ws.Range("A1").Value = "処理済み"
Continue:
Next ws
MsgBox "処理が完了しました(集計・目次シートを除く)。"
End Sub
' ============================
' よりスマートな書き方(Select Case版)
' ============================
Sub 特定シート除外ループ_SelectCase版()
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
Select Case ws.Name
Case "集計", "目次", "テンプレート" ' 除外するシート名を列挙
' 何もしない(スキップ)
Case Else
' 処理対象シートへの処理
ws.Range("A1").Value = "処理済み"
End Select
Next ws
MsgBox "処理が完了しました。"
End Sub
' ============================
' シート名が特定の文字で始まるものだけ処理する(Like演算子)
' ============================
Sub 特定名称シートのみ処理()
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
' シート名が「月次_」で始まるシートのみ処理する
If ws.Name Like "月次_*" Then
ws.Range("A1").Value = "月次処理済み"
End If
Next ws
MsgBox "月次シートの処理が完了しました。"
End Sub
パターン3:全シートのデータを1枚のシートに集約する
月別・支店別・担当者別などのシートに分かれているデータを1枚の集計シートにまとめる処理は、実務で最もニーズが高いパターンです。各シートのデータを順番に集計シートに貼り付けていく処理を解説します。
' ============================
' 全シートのデータを「集計」シートに縦方向に集約する
' ============================
Sub 全シートデータ集約()
Dim ws As Worksheet
Dim 集計シート As Worksheet
Dim 集計最終行 As Long
Dim 各シート最終行 As Long
' 集計シートを変数に格納する
Set 集計シート = ThisWorkbook.Worksheets("集計")
' 集計シートの既存データをクリアする(ヘッダー行1行目は残す)
If 集計シート.Cells(Rows.Count, 1).End(xlUp).Row > 1 Then
集計シート.Rows("2:" & 集計シート.Cells(Rows.Count, 1).End(xlUp).Row).Delete
End If
' 各シートをループして集計シートにデータをコピーする
For Each ws In ThisWorkbook.Worksheets
' 集計シート自身はスキップする
If ws.Name = "集計" Then GoTo Continue
' 各シートのデータ最終行を取得する
各シート最終行 = ws.Cells(Rows.Count, 1).End(xlUp).Row
' データが2行目以降にある場合のみ処理する(1行目はヘッダーとして除く)
If 各シート最終行 >= 2 Then
' 集計シートの現在の最終行を取得する
集計最終行 = 集計シート.Cells(Rows.Count, 1).End(xlUp).Row + 1
' 各シートの2行目から最終行のデータをコピーして集計シートに貼り付ける
ws.Rows("2:" & 各シート最終行).Copy _
Destination:=集計シート.Cells(集計最終行, 1)
End If
Continue:
Next ws
MsgBox "全シートのデータ集約が完了しました。"
End Sub
パターン4:全シートをCSVまたはPDFに一括出力する
月次報告書・請求書・明細書など複数シートを一度にCSVまたはPDFとして書き出す処理です。
' ============================
' 全シートを個別のCSVファイルとして一括出力する
' ============================
Sub 全シートCSV一括出力()
Dim ws As Worksheet
Dim 保存先パス As String
' 保存先フォルダのパスを指定する(末尾に\を付ける)
保存先パス = ThisWorkbook.Path & "\" ' 元のブックと同じフォルダに保存
For Each ws In ThisWorkbook.Worksheets
' 各シートを新規ブックにコピーしてCSV保存する
ws.Copy
ActiveWorkbook.SaveAs Filename:=保存先パス & ws.Name & ".csv", _
FileFormat:=xlCSV, CreateBackup:=False
ActiveWorkbook.Close SaveChanges:=False
Next ws
MsgBox "全シートのCSV出力が完了しました。" & vbCrLf & _
"保存先:" & 保存先パス
End Sub
' ============================
' 全シートをPDFとして一括出力する
' ============================
Sub 全シートPDF一括出力()
Dim ws As Worksheet
Dim 保存先パス As String
保存先パス = ThisWorkbook.Path & "\"
For Each ws In ThisWorkbook.Worksheets
ws.ExportAsFixedFormat _
Type:=xlTypePDF, _
Filename:=保存先パス & ws.Name & ".pdf", _
Quality:=xlQualityStandard, _
IncludeDocProperties:=True, _
IgnorePrintAreas:=False, _
OpenAfterPublish:=False
Next ws
MsgBox "全シートのPDF出力が完了しました。" & vbCrLf & _
"保存先:" & 保存先パス
End Sub
パターン5:全シートの最終行を取得して動的に処理する
各シートのデータ量が異なる場合は、毎回最終行を動的に取得してから処理する書き方が必要です。固定の行番号でコードを書くと、データが増減したときに対応できなくなります。
' ============================
' 各シートの最終行を動的に取得してA列に連番を入力する
' ============================
Sub 最終行動的取得サンプル()
Dim ws As Worksheet
Dim 最終行 As Long
Dim i As Long
For Each ws In ThisWorkbook.Worksheets
' A列の最終行を取得する(データが入っている一番下の行番号)
最終行 = ws.Cells(Rows.Count, 1).End(xlUp).Row
' 2行目(ヘッダーの次)から最終行まで処理する
For i = 2 To 最終行
' B列に「処理済み」を入力する例
ws.Cells(i, 2).Value = "処理済み"
Next i
Next ws
MsgBox "全シートの処理が完了しました。"
End Sub
' ============================
' 最終行・最終列の取得方法の比較
' ============================
Sub 最終行最終列取得サンプル()
Dim ws As Worksheet
Set ws = ActiveSheet
' A列の最終行を取得する(最も一般的な方法)
Dim 最終行A列 As Long
最終行A列 = ws.Cells(Rows.Count, 1).End(xlUp).Row
Debug.Print "A列の最終行:" & 最終行A列
' 1行目の最終列を取得する
Dim 最終列1行目 As Long
最終列1行目 = ws.Cells(1, Columns.Count).End(xlToLeft).Column
Debug.Print "1行目の最終列:" & 最終列1行目
' シート全体の使用範囲の最終行・最終列を取得する(UsedRangeを使う方法)
Dim 使用範囲最終行 As Long
Dim 使用範囲最終列 As Long
使用範囲最終行 = ws.UsedRange.Rows.Count
使用範囲最終列 = ws.UsedRange.Columns.Count
Debug.Print "UsedRange最終行:" & 使用範囲最終行
Debug.Print "UsedRange最終列:" & 使用範囲最終列
End Sub
パターン6:インデックス番号を使った柔軟な範囲指定
「2枚目から最後まで処理する(1枚目は目次シートなので除外)」「偶数番目のシートだけ処理する」など、シートの位置を基準に処理範囲を指定する場合はFor〜Next(インデックス番号指定)が便利です。
' ============================
' 2枚目から最後のシートまでループする(1枚目を除外)
' ============================
Sub 2枚目から最後まで処理()
Dim i As Long
' i=2からスタートすることで1枚目(目次シートなど)をスキップする
For i = 2 To ThisWorkbook.Worksheets.Count
Worksheets(i).Range("A1").Value = "処理済み"
Next i
MsgBox "2枚目以降の全シートの処理が完了しました。"
End Sub
' ============================
' 最後から逆順にシートをループする(シートを削除する処理の場合に必要)
' ============================
Sub 逆順ループで空シート削除()
Dim i As Long
' シートを削除するときは後ろから前にループしないとインデックスがずれる
For i = ThisWorkbook.Worksheets.Count To 1 Step -1
' A1セルが空のシートを削除する
If Worksheets(i).Range("A1").Value = "" Then
' 最低1枚のシートは残す必要があるためカウントを確認
If ThisWorkbook.Worksheets.Count > 1 Then
Application.DisplayAlerts = False ' 確認ダイアログを非表示
Worksheets(i).Delete
Application.DisplayAlerts = True
End If
End If
Next i
MsgBox "空シートの削除が完了しました。"
End Sub
処理速度を大幅に上げる3つのテクニック
シート数が多い場合やデータ量が大きい場合、ループ処理が遅くなることがあります。以下の3つの設定を処理の前後に追加するだけで処理速度が大幅に改善されます。
' ============================
' 高速化の設定を組み込んだループ処理の基本テンプレート
' ============================
Sub 高速化テンプレート()
' ===== 処理前の高速化設定 =====
Application.ScreenUpdating = False ' 画面更新を停止(最も効果が大きい)
Application.Calculation = xlCalculationManual ' 自動計算を停止
Application.EnableEvents = False ' イベント処理を停止
' エラーが発生した場合でも設定を元に戻せるようにエラーハンドリングを設定
On Error GoTo ErrorHandler
' ===== ここにループ処理を書く =====
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
ws.Range("A1").Value = "処理済み"
' 実際の処理をここに記述する
Next ws
MsgBox "処理が完了しました。"
' ===== 処理後に設定を元に戻す =====
ErrorHandler:
Application.ScreenUpdating = True ' 画面更新を再開
Application.Calculation = xlCalculationAutomatic ' 自動計算を再開
Application.EnableEvents = True ' イベント処理を再開
' エラーが発生していた場合はメッセージを表示する
If Err.Number <> 0 Then
MsgBox "エラーが発生しました。" & vbCrLf & _
"エラー番号:" & Err.Number & vbCrLf & _
"内容:" & Err.Description
End If
End Sub
' 高速化の効果の目安
' Application.ScreenUpdating = False
' → シートが切り替わるたびの画面描画を止めるため最も効果が大きい
' → シートが10枚・100枚あっても画面がちらつかず高速に処理される
' Application.Calculation = xlCalculationManual
' → ループ中にセルの値が変わるたびに自動計算が走るのを止める
' → 数式が多いブックで特に効果的
' Application.EnableEvents = False
' → Worksheet_Changeなどのイベントマクロがループごとに発火するのを止める
' → イベントマクロが設定されているブックで処理が遅い場合に効果的
よくあるエラーと対処法
「インデックスが有効範囲にありません(実行時エラー’9’)」が発生する
存在しないシート名・シート番号を指定したときに発生します。シート名のスペルミスや削除済みのシートを参照していないかを確認してください。
' ============================
' 実行時エラー'9'が発生する例
' ============================
Sub エラー例_シート名ミス()
' 「売上データ」というシートが存在しない場合はエラーになる
Worksheets("売上データ").Range("A1").Value = "テスト" ' ← 実行時エラー'9'
' シートが存在するかチェックしてからアクセスする
Dim ws As Worksheet
Dim シート名 As String
シート名 = "売上データ"
For Each ws In ThisWorkbook.Worksheets
If ws.Name = シート名 Then
ws.Range("A1").Value = "テスト"
Exit For ' 見つかったらループを終了
End If
Next ws
End Sub
' ============================
' シートの存在確認を関数化しておくと便利
' ============================
Function シート存在確認(シート名 As String) As Boolean
Dim ws As Worksheet
シート存在確認 = False
For Each ws In ThisWorkbook.Worksheets
If ws.Name = シート名 Then
シート存在確認 = True
Exit Function
End If
Next ws
End Function
' 使い方
Sub 存在確認付き処理()
If シート存在確認("売上データ") Then
Worksheets("売上データ").Range("A1").Value = "処理済み"
Else
MsgBox "「売上データ」シートが見つかりませんでした。"
End If
End Sub
ループ処理でシートを削除するとインデックスがずれる
For〜Nextでシートをループしながら途中でシートを削除すると、インデックス番号がずれて正しく動作しません。削除処理を伴うループは必ず後ろから前に向かって逆順で実行してください。
' ============================
' 誤った例:前から順に削除するとインデックスがずれる
' ============================
Sub 誤り_前から削除()
Dim i As Long
For i = 1 To ThisWorkbook.Worksheets.Count ' ← カウントが変わるためNG
If Worksheets(i).Range("A1").Value = "" Then
Worksheets(i).Delete ' 削除するとインデックスがずれて一部スキップされる
End If
Next i
End Sub
' ============================
' 正しい例:後ろから前に向かって削除する
' ============================
Sub 正しい_後ろから削除()
Dim i As Long
Application.DisplayAlerts = False ' 削除確認ダイアログを非表示
For i = ThisWorkbook.Worksheets.Count To 1 Step -1 ' ← Step -1で逆順ループ
If Worksheets(i).Range("A1").Value = "" Then
If ThisWorkbook.Worksheets.Count > 1 Then ' 最低1枚は残す
Worksheets(i).Delete
End If
End If
Next i
Application.DisplayAlerts = True
MsgBox "削除処理が完了しました。"
End Sub
コピペしてすぐ使えるテンプレートまとめ
以下は複数シートのループ処理の基本テンプレートです。コメント行の「処理をここに書く」の部分を自分のコードに差し替えるだけで使えます。
' ============================
' 【テンプレート1】全シート一括処理(最もシンプル)
' ============================
Sub テンプレート_全シート()
Dim ws As Worksheet
Application.ScreenUpdating = False
For Each ws In ThisWorkbook.Worksheets
' ===== 処理をここに書く =====
ws.Range("A1").Value = "サンプル"
' ============================
Next ws
Application.ScreenUpdating = True
MsgBox "完了しました。"
End Sub
' ============================
' 【テンプレート2】特定シートを除外して処理
' ============================
Sub テンプレート_除外あり()
Dim ws As Worksheet
Application.ScreenUpdating = False
For Each ws In ThisWorkbook.Worksheets
If ws.Name = "集計" Or ws.Name = "目次" Then GoTo Continue
' ===== 処理をここに書く =====
ws.Range("A1").Value = "サンプル"
' ============================
Continue:
Next ws
Application.ScreenUpdating = True
MsgBox "完了しました。"
End Sub
' ============================
' 【テンプレート3】2枚目から最後まで処理
' ============================
Sub テンプレート_2枚目から()
Dim i As Long
Application.ScreenUpdating = False
For i = 2 To ThisWorkbook.Worksheets.Count
' ===== 処理をここに書く =====
Worksheets(i).Range("A1").Value = "サンプル"
' ============================
Next i
Application.ScreenUpdating = True
MsgBox "完了しました。"
End Sub
まとめ:複数シートのループ処理は2つの構文を覚えるだけ
Excelマクロで複数シートを一括処理するには、以下の2つの構文を使い分けるだけです。
- For Each ws In ThisWorkbook.Worksheets〜Next ws:全シートを同じ処理で一括操作する場合に推奨。コードがシンプルで読みやすい
- For i = 1 To Worksheets.Count〜Next i:「2枚目から最後まで」「偶数番目だけ」など範囲を柔軟に指定したい場合に使う
最も大切なポイントは「ループ内でセルを操作するときは必ずws.やWorksheets(i).を頭に付けて処理対象シートを明示すること」です。また、処理の前後に Application.ScreenUpdating = False / True を設定するだけで、シート数が多い場合でも高速に処理が完了します。本記事のテンプレートをコピーして「処理をここに書く」の部分を書き換えるだけで、すぐに実務で使えるマクロが完成します。