【VBA】テンプレートシートをコピーして月別・担当者別に量産する方法(コピペOK)

VBA
スポンサーリンク

スポンサーリンク

この記事でできること

VBAでテンプレートシートをコピーし、月別(4月〜3月)・担当者別にシートを一括生成できるようになる。

  • 対象:テンプレートシートを手作業でコピー&リネームしている人
  • 所要時間:コピペ → 実行まで5分

どんな場面で使う?

  • 月別シートの一括作成: 4月〜3月の12ヶ月分のシートをテンプレートから一気に作成する
  • 担当者別シートの量産: 営業担当者や拠点ごとにシートを作成し、名前やタイトルまで自動書き換え
  • 年度替わりの準備作業: 新年度のブックを作るとき、12ヶ月分×5担当者=60シートを手作業で作る代わりにVBAで一発生成
  • プロジェクト別の管理シート作成: プロジェクト一覧からテンプレートをコピーして、プロジェクト名・開始日を自動設定
  • イベントや研修の参加者別シート: 参加者リストからシートを量産し、名前や所属を自動転記

完成イメージ(Before / After)

Before(手作業)

操作 回数
シートタブを右クリック →「移動またはコピー」 12回(月別の場合)
シート名を1つずつ変更 12回
テンプレート内のタイトルセルを手修正 12回

合計36回の手作業。担当者が10人なら、さらに10倍。

After(VBA実行後)

  • 実行ボタンを1回押すだけで、テンプレートシートから12枚(月別)や任意の枚数(担当者別)のシートが自動生成される
  • シート名もセル値も自動で書き換え済み

導入

自分も毎月、テンプレートシートを右クリック → コピー → シート名変更 → タイトルセル修正、を12回繰り返していた。担当者が5人いるチームだと、12ヶ月分×5人=60シート。右クリック → コピー → 名前変更を60回繰り返すと、それだけで1時間以上かかる。しかもシート名を間違えて作り直したり、コピー元を間違えて書式が崩れたりで、精神的にもかなりキツい作業だった。

VBAで自動化してからは、リストシートに名前を並べてボタンを1回押すだけで、60枚のシートが数秒で揃うようになった。シート名もセル内のタイトルも自動で書き換わるので、コピー後の手修正がゼロ。

この記事で、同じように手作業のシートコピーに時間を取られている人がサクッと自動化できるようになればうれしい。

前提条件

– Excel 2016以降 / Microsoft 365

– Windows 10/11

– ファイルは .xlsm(マクロ有効ブック)で保存

– コードは 標準モジュール に貼り付け

– 実行方法:Alt + F8 →マクロ選択 → 実行

VBE(コードを書く画面)の開き方や標準モジュールの挿入がわからない場合は、シートを別ブックにコピー・移動する方法の手順を参考にしてください。

手順

  1. Excelファイルを .xlsm で保存する
    • ファイル → 名前を付けて保存 → ファイルの種類を「Excelマクロ有効ブック (*.xlsm)」に変更
    • テンプレートシートを用意する
    • シート名を「テンプレート」にする(コード内のシート名と合わせる)
    • VBEを開く
    • Alt + F11 キーを押す
    • 標準モジュールを挿入する
    • VBE画面の左側「VBAProject」を右クリック → 挿入 → 標準モジュール
    • コードを貼り付ける
    • 下記のコードをコピーして貼り付ける
    • マクロを実行する
    • Alt + F8 → マクロ名を選択 → 実行

実行前に必ずバックアップを取ってください。 シートのコピーは元に戻す(Ctrl+Z)が効きません。

基本コード(月別シートを単純コピー)

まずはこれで動く最小限のコード。テンプレートシートを12回コピーして、4月〜3月のシート名を付ける。


Sub テンプレートから月別シート作成()
    Dim wsTemplate As Worksheet
    Dim i As Long
    Dim sheetName As String

    Set wsTemplate = ThisWorkbook.Worksheets("テンプレート")

    For i = 4 To 15
        ' 4月〜翌3月の月名を生成
        If i <= 12 Then
            sheetName = i & "月"
        Else
            sheetName = (i - 12) & "月"
        End If

        ' 同名シートが既にあればスキップ
        If Not SheetExists(sheetName) Then
            wsTemplate.Copy After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count)
            ActiveSheet.Name = sheetName
        End If
    Next i

    MsgBox "月別シートの作成が完了しました。", vbInformation
End Sub

Function SheetExists(ByVal name As String) As Boolean
    Dim ws As Worksheet
    On Error Resume Next
    Set ws = ThisWorkbook.Worksheets(name)
    On Error GoTo 0
    SheetExists = Not ws Is Nothing
End Function

ポイント

コード解説: For i = 4 To 15 のループで4月〜翌3月の12ヶ月分を処理している。i が12以下なら i & "月"(4月〜12月)、13以上なら (i - 12) & "月"(1月〜3月)としてシート名を生成する。wsTemplate.Copy After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count) はテンプレートシートをブックの末尾にコピーする命令で、コピー直後に ActiveSheet が新しいシートを指すので、そこで .Name プロパティにシート名を設定している。SheetExists 関数は On Error Resume Next を使って同名シートの取得を試み、エラーが出れば存在しない(False)と判定するシンプルなテクニック。

実務版コード(リストからシート名を読み取って量産+セル値書き換え)

自分はこの実務版を使うようになってから、月別だけでなく担当者別・拠点別のシート作成も全部これ1本で回している。テンプレートの中身(タイトルや日付)まで自動で書き換わるので、コピー後の手修正がゼロになった。


Sub テンプレートからシート量産()
    '================================================
    ' 「リスト」シートのA列にシート名の一覧を用意しておく
    ' テンプレートシートをコピーし、シート名とセル値を自動設定
    '================================================

    Dim wsTemplate As Worksheet
    Dim wsList As Worksheet
    Dim wsNew As Worksheet
    Dim lastRow As Long
    Dim i As Long
    Dim newName As String

    Set wsTemplate = ThisWorkbook.Worksheets("テンプレート")
    Set wsList = ThisWorkbook.Worksheets("リスト")

    ' リストシートのA列からシート名を取得
    lastRow = wsList.Cells(wsList.Rows.Count, "A").End(xlUp).Row

    If lastRow < 2 Then
        MsgBox "リストシートのA列(A2以降)にシート名を入力してください。", vbExclamation
        Exit Sub
    End If

    ' 画面更新を停止して高速化
    Application.ScreenUpdating = False

    For i = 2 To lastRow
        newName = Trim(wsList.Cells(i, "A").Value)

        ' 空白セルはスキップ
        If newName = "" Then GoTo NextItem

        ' シート名に使えない文字をチェック
        If InStr(newName, ":") > 0 Or InStr(newName, "\") > 0 Or _
           InStr(newName, "/") > 0 Or InStr(newName, "?") > 0 Or _
           InStr(newName, "*") > 0 Or InStr(newName, "[") > 0 Or _
           InStr(newName, "]") > 0 Then
            Debug.Print "スキップ(禁止文字): " & newName
            GoTo NextItem
        End If

        ' シート名が31文字を超える場合はスキップ
        If Len(newName) > 31 Then
            Debug.Print "スキップ(31文字超): " & newName
            GoTo NextItem
        End If

        ' 同名シートが既にあればスキップ
        If SheetExists(newName) Then
            Debug.Print "スキップ(既存): " & newName
            GoTo NextItem
        End If

        ' テンプレートをコピー
        wsTemplate.Copy After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count)
        Set wsNew = ActiveSheet
        wsNew.Name = newName

        ' ---- ここが追加:テンプレート内のセル値を書き換え ----
        ' B列の値があればセルA1(タイトル)に設定
        If wsList.Cells(i, "B").Value <> "" Then
            wsNew.Range("A1").Value = wsList.Cells(i, "B").Value
        Else
            wsNew.Range("A1").Value = newName
        End If

        ' C列の値があればセルA2(日付や補足)に設定
        If wsList.Cells(i, "C").Value <> "" Then
            wsNew.Range("A2").Value = wsList.Cells(i, "C").Value
        End If
        ' ---- 追加ここまで ----

NextItem:
    Next i

    Application.ScreenUpdating = True

    MsgBox "シートの量産が完了しました。", vbInformation
End Sub

Function SheetExists(ByVal name As String) As Boolean
    Dim ws As Worksheet
    On Error Resume Next
    Set ws = ThisWorkbook.Worksheets(name)
    On Error GoTo 0
    SheetExists = Not ws Is Nothing
End Function

リストシートの構成例

A列(シート名) B列(タイトル) C列(補足)
1行目 シート名 タイトル 補足
2行目 4月 4月度 売上報告 2026年4月
3行目 5月 5月度 売上報告 2026年5月
4行目 田中 田中担当分 東京エリア

この方法なら、リストシートの内容を変えるだけで月別でも担当者別でも拠点別でも対応できる。同僚に渡すときも「リストシートに名前を入れて実行してね」で済むので、VBAを知らない人でも使える。

落とし穴

自分も最初、シート名に「/」を含む名前(「2026/04」など)を入れてしまい、実行時エラー1004で止まった。原因がわかるまで30分くらい溶かした。

# 症状 原因 対策
1 実行時エラー 1004「そのシート名は正しくありません」 シート名に使えない文字(: \ / ? * [ ])が含まれている 実務版コードでは禁止文字チェックを追加済み。リストに入力する名前を事前に確認する
2 実行時エラー 1004「同じ名前は使用できません」 同名のシートが既に存在する SheetExists 関数で事前チェックしている。2回目以降の実行でも安全
3 シート名が途中で切れる シート名は最大31文字の制限がある 31文字を超える名前は実務版コードでスキップされる。短い名前にする
4 テンプレートの書式が崩れる テンプレートシートにフィルタやグループ化が設定されていると、コピー時に意図しない状態になることがある コピー前にテンプレートのフィルタを解除しておく。複数シートに同じ処理を一括実行する方法でフィルタ解除を自動化できる
5 シートが大量にできて動作が重い シート数が多すぎるとExcel自体の動作が遅くなる 1ブックあたり50枚程度を目安にする。それ以上はシートを別ブックにコピー・移動する方法でブックを分割する
6 Ctrl+Z(元に戻す)が効かない VBAで追加したシートは「元に戻す」の対象外 実行前にバックアップを取る習慣をつける

VBA シートコピー 名前 重複エラーの対処

Sheet.Copy でシートをコピーした後に ActiveSheet.Name = "4月" のようにシート名を設定すると、同名のシートが既に存在する場合に実行時エラー1004が発生する。このエラーを防ぐには、名前を設定する前に SheetExists 関数で同名シートの有無をチェックする(実務版コードでは対応済み)。もう1つのパターンとして、2回目の実行時に前回作成したシートが残っている場合がある。この場合は、既存シートを削除してから再実行するか、スキップして次に進む設計にする。削除する場合は Application.DisplayAlerts = False でExcelの確認ダイアログを抑制する必要がある。

VBA テンプレート 量産 遅い場合の高速化

シートを50枚以上コピーすると処理が目に見えて遅くなることがある。まず Application.ScreenUpdating = False で画面更新を停止する(実務版コードでは対応済み)。これだけで体感速度が大幅に改善する。それでも遅い場合は、Application.Calculation = xlCalculationManual で自動計算を一時停止し、処理後に xlCalculationAutomatic に戻す。テンプレートに大量の数式や条件付き書式が入っていると、コピーのたびに再計算が走るため、これが効果的。詳しくは 処理時間を計測してボトルネックを見つける方法 でどこに時間がかかっているか特定できる。

コピーしたシートの並び順がおかしい場合

Copy After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count) は常にブック末尾にシートを追加するので、リストの順番どおりにシートが並ぶ。ただし、途中でエラーが発生してスキップした場合、順番が飛ぶことがある。また、既存のシートが間に挟まっていると意図した並び順にならない。並び順を厳密に制御したい場合は、全シート作成後に Worksheets("4月").Move After:=Worksheets("テンプレート") のように Move メソッドで並べ替えるとよい。

FAQ

Q1. テンプレートシートに数式が入っていても大丈夫?

大丈夫です。Sheet.Copy はセルの値・数式・書式・条件付き書式・入力規則をすべてコピーします。ただし、他のシートを参照する数式(例:=Sheet1!A1)は参照先がコピー元のままになる場合があるので、コピー後に確認してください。

Q2. 年度(4月始まり)の順番でシートを並べたいが、順番がずれる

基本コードでは Copy After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count) で末尾に追加しているため、4月→5月→…→3月の順番になります。リストシートのA列に並べた順番どおりにシートが作成されます。

Q3. 特定のシートだけ削除してやり直したい

手動でシートタブを右クリック → 削除でOKです。VBAで一括削除する場合は、Application.DisplayAlerts = False を使いますが、削除は元に戻せないので必ずバックアップを取ってから実行してください。

Q4. ボタンを設置してワンクリックで実行したい

Excelで請求書を自動作成する方法でもボタン実行の手順を紹介しています。シート上にボタンを配置し、このマクロを割り当てれば、VBEを開かなくてもワンクリックで実行できます。

Q5. シート名ではなく日付(2026-04など)で作りたい

リストシートのA列に「2026-04」「2026-05」…と入力すればOKです。ただし「/」はシート名に使えないため、「2026/04」ではなく「2026-04」のようにハイフンで区切ってください。

まとめ

この記事では、VBAでテンプレートシートをコピーして月別・担当者別にシートを量産する方法を紹介した。手作業で右クリック → コピー → 名前変更を何十回も繰り返していた作業が、リストを用意してマクロを1回実行するだけで完了する。シート名の重複チェックや禁止文字チェックも入っているので、誰が何回実行しても安全に動作する。

  • 基本コード:テンプレートを12回コピーして月名を付けるシンプルな方法
  • 実務版コード:リストシートからシート名を読み取り、セル値まで自動書き換え

リストシートの内容を変えるだけで、月別・担当者別・拠点別など自由に応用できる。VBAを知らない同僚にも「リストに名前を入れて実行ボタンを押すだけ」で渡せるのが、この方法の大きな利点。

次にやりたくなること

テンプレートからシートを量産できたら、次はこのあたりが気になるはず。

コメント

タイトルとURLをコピーしました