拠点別、月別、担当者別など、同じフォーマットのシートが何枚にも分かれていて、集計のたびに1枚ずつコピー&ペーストしていませんか。
シートが数枚のうちは我慢できても、枚数が増えるほど「貼り付け漏れ」「集計後の行ズレ」といったミスが起きやすくなります。
この記事では、複数シートに分かれたデータを1つのシートに自動でまとめるVBAマクロの作り方を、シートの増減があっても書き直しが不要な汎用的な書き方で解説します。前回の「Excel VBA初心者がまず覚えるべき基本構文まとめ」ではVBAの基本構文(For〜Next・End(xlUp)など)を1つずつ紹介しましたが、今回はそれらを実務でどう組み合わせて使うかという実践編にあたります。この記事だけを読んでも理解できる内容です。
このマクロでできること
- 作業時間の削減:シートが何枚あっても、実行するだけで集計シートが自動生成される
- 転記ミスの防止:手作業のコピペで起きがちな貼り付け漏れ・範囲ズレがなくなる
- メンテナンス性:シートが増えても減っても、コードを書き直す必要がない(除外するシート名を1つ指定するだけ)
全体の仕組み(設計の考え方)
今回作るマクロの流れは、次の4ステップです。
- ブック内のすべてのシートを1枚ずつループで処理する
- 集約先の集計シート自身は処理の対象から除外する
- 各シートの最終行を取得し、データ部分を集計シートの末尾にコピーする
- ヘッダー行(見出し行)は最初の1回だけ集計シートにコピーする
全体の流れ(イメージ)

集約先シートを対象から除外し忘れると、集計シート自身のデータをさらに集計シートへ追記してしまい、実行するたびに行がどんどん増え続けるという初心者が特にはまりやすい不具合になります。この点はコード内でも明示的にチェックします。
サンプルコード
このマクロが対象とするのは、次のようなExcelファイルです。
- 拠点別・月別・担当者別などで、同じ列構成のシートが複数枚あるブック
- 各シート(集約先シートを除く)は1行目が見出し行、2行目以降がデータという構成
- 集約先のシート名は「集計」(存在しなければマクロが自動生成する)
想定するExcelファイル(実例)

以下のサンプルコードは、この構成のExcelファイルにそのまま貼り付けて動かせます。
Sub ConsolidateSheets()
Dim ws As Worksheet
Dim wsSummary As Worksheet
Dim summaryLastRow As Long
Dim srcLastRow As Long
Dim headerCopied As Boolean
' 基本形:集約先シート名は定数で一元管理する
Const SUMMARY_SHEET_NAME As String = "集計"
On Error GoTo ErrHandler
' 集約先シートを取得(存在しなければ新規作成し、あれば前回分をクリア)
On Error Resume Next
Set wsSummary = ThisWorkbook.Worksheets(SUMMARY_SHEET_NAME)
On Error GoTo ErrHandler
If wsSummary Is Nothing Then
Set wsSummary = ThisWorkbook.Worksheets.Add(After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count))
wsSummary.Name = SUMMARY_SHEET_NAME
Else
wsSummary.Cells.Clear
End If
headerCopied = False
' ①全シートを1枚ずつループ処理する
For Each ws In ThisWorkbook.Worksheets
' ②集計シート自身は処理対象から除外する(ここを忘れると行が際限なく増え続ける)
If ws.Name <> SUMMARY_SHEET_NAME Then
' ③各シートの最終行(データの末尾)を取得する
srcLastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
If srcLastRow >= 1 Then
If Not headerCopied Then
' 見出し行(1行目)のコピーは最初の1回だけ行う
ws.Rows(1).Copy Destination:=wsSummary.Rows(1)
headerCopied = True
End If
If srcLastRow >= 2 Then
' ④データ部分を集計シートの末尾に追記する
summaryLastRow = wsSummary.Cells(wsSummary.Rows.Count, "A").End(xlUp).Row
ws.Range(ws.Rows(2), ws.Rows(srcLastRow)).Copy _
Destination:=wsSummary.Cells(summaryLastRow + 1, "A")
End If
End If
End If
Next ws
MsgBox "集計が完了しました。", vbInformation
Exit Sub
ErrHandler:
MsgBox "エラーが発生しました:" & Err.Description, vbCritical
End Sub
コードのポイント
- Excelのシート数が増減してもコードの書き直しが不要です。
⇒ブック内の全シートを1枚ずつ処理する
For Each ws In ThisWorkbook.Worksheets
という書き方をしているためです。 - 集計先のシート名を後から変更したくなっても、直す場所は1箇所で済みます。
⇒シート名の「集計」をコードのあちこちに書く代わりに、
Const SUMMARY_SHEET_NAME As String = "集計"
という1行にまとめているためです。
もしシート名を「まとめ」に変えたくなっても、この1行を書き換えるだけで済みます。 - 見出し行は1シート目からコピーされたら、2シート目以降ではコピーされません。
⇒headerCopiedという「見出し行をコピー済みかどうか」を覚えておくスイッチを用意し、
最初の1回でスイッチをONに切り替え、以降はそのスイッチを見てスキップしているためです。 - 集計シートにデータを追記するたびに、必ず「今ある最後の行の続き」から書き込まれます。
⇒シートを1枚処理するたびにsummaryLastRowで集計シートの最終行を測り直しているため、
追記位置が前のシートを書き込んだ直後の状態に常に更新されるからです。
実行結果(イメージ)

東京支店・大阪支店・名古屋支店、3枚すべてのシートのデータが集計シートにまとめられます。
つまずきやすいポイント
| 症状 | 原因 | 対処 |
|---|---|---|
| 行が実行のたびに際限なく増え続ける | 集計シート自身をループから除外していない | If ws.Name <> SUMMARY_SHEET_NAME Then を必ず入れる |
| ヘッダー行が何行も重複コピーされる | 毎シートでヘッダーをコピーしている | headerCopiedフラグで最初の1回だけコピーする |
| 実行時エラー「1004」が出る | 集計先シートが保護されている、またはヘッダー行に結合セルが含まれている | シートの保護を解除する/結合セルを解除してから実行する |
| 集計結果の列がズレる | シートごとに列の並びが違う | 集計対象シートの列構成を事前に統一する |
| 集計結果の行数が想定より少ない | 1行目に見出しがないシートが混ざっている | 全シートで「1行目は見出し」に統一する |
応用編:条件を絞って集計するには
このマクロは、集計後にどう使うかに応じてさらに工夫の余地があります。あくまで一例ですが、次のような拡張が考えられます。
① 条件に合う行だけ集計する
「金額が一定以上の行だけ」のように対象を絞りたい場合は、コピー処理の直前にIf文を1つ挟むだけで対応できます。
② 集計後にピボットテーブルで分析する
集計シートが完成したら、そこにピボットテーブルを設定すれば、拠点別・月別など切り口を変えた分析がボタン操作だけで行えます。
まとめ
複数シートの集計は、シート数がその都度変わる実務では手作業に頼りがちな作業ですが、「全シートをループ」「集約先を除外」「ヘッダーは1回だけ」という3つのポイントさえ押さえれば、シート数の増減を気にせず使えるマクロになります。
Excel VBAで見積書・請求書の作成を自動化する方法で紹介した「入力→転記→出力」も、Excel VBA初心者がまず覚えるべき基本構文まとめで紹介した基本構文も、根っこにあるのは同じ「ループでセルを読み書きする」という考え方です。ぜひ手元のExcelでシート数を変えながら試してみてください。
このマクロを自分で書く代わりにChatGPTに書かせる方法は、ChatGPTにVBAコードを書かせて業務を自動化する方法で解説しています。VBAとPython、どちらを学ぶべきか迷っている場合はVBAとPython、業務自動化にはどちらを学ぶべきか比較も参考にしてください。