Excel VBAでは、新しい空白シートを追加するだけでなく、すでに存在しているシートをコピーして、新しいシートとして追加できます。
例えば、「テンプレート」というシートを用意しておき、「4月」「5月」「6月」のような同じレイアウトのシートを作成する場合、毎回セルの書式や数式、項目名などをVBAで設定するのは効率的ではありません。
このような場合に便利なのが、ワークシートのCopyメソッドです。
既存シートをコピーすれば、元のシートをベースとして新しいシートを作成できるため、帳票や月次資料、部署別シートなどを自動生成するときにも活用できます。
ただし、VBAでシートをコピーするときは「どのシートをコピーするのか」だけでなく、コピーしたシートをどこへ追加するのかまで明確にしておくことが重要です。
この記事では、Copyメソッドを使って既存シートを複製し、同じブック内へ新しいシートとして追加する基本から、実務で扱いやすいコードの書き方まで解説します。
✅ VBAでシートをコピーして追加する基本
VBAで既存シートを複製するときに注意したいのが、「シートを追加する処理」と「シートをコピーする処理」は同じではないという点です。空白シートを作成したいだけなら別の方法がありますが、既存シートのレイアウトを引き継ぎたい場合はCopyメソッドが適しています。ここを区別せずにコードを作ると、シート追加後に書式や数式をもう一度設定する処理が必要になり、コードが必要以上に長くなることがあります。
また、コピー位置を指定しないコードは、想定とは異なるブックが作成される原因にもなります。特に業務用マクロでは、実行するたびに同じ結果になるよう、コピー元とコピー先をコード上で明確にすることが重要です。
・Copyメソッドで既存シートを複製する仕組み
既存のワークシートをコピーする場合は、WorksheetオブジェクトのCopyメソッドを使用します。
基本的な考え方は次のとおりです。
コピーするシート.Copy Before:=コピー先のシート
または、
コピーするシート.Copy After:=コピー先のシート
Beforeを使用すると指定したシートの前、Afterを使用すると指定したシートの後ろへコピーしたシートが追加されます。
例えば、「テンプレート」シートを「集計」シートの後ろへコピーする場合は、次のように記述できます。
Sub CopyTemplateSheet()
ThisWorkbook.Worksheets("テンプレート").Copy _
After:=ThisWorkbook.Worksheets("集計")
End Sub
処理の流れはシンプルです。
ThisWorkbookでマクロを保存しているブックを指定するWorksheets("テンプレート")でコピー元を指定するCopyメソッドを実行するAfterで「集計」シートの後ろをコピー先として指定する
このコードを実行すると、「テンプレート」の内容を引き継いだコピーが「集計」シートの後ろへ追加されます。
ここで重要なのは、単に
Worksheets("テンプレート").Copy
としないことです。
コピー位置を指定せずにCopyメソッドを実行すると、同じブックにシートが追加されるのではなく、コピーされたシートを含む新しいブックが作成されます。
「シートをコピーして今のブックへ追加したかったのに、別のExcelブックが開いた」という場合は、BeforeまたはAfterの指定を確認しましょう。
・BeforeとAfterでコピー位置を指定する
コピーしたシートをどこへ追加するかによって、BeforeとAfterを使い分けます。
例えば、「入力」シートの前へ「テンプレート」をコピーする場合は次のように記述します。
Sub CopySheetBeforeInput()
ThisWorkbook.Worksheets("テンプレート").Copy _
Before:=ThisWorkbook.Worksheets("入力")
End Sub
反対に、「入力」シートの後ろへ追加する場合は次のコードです。
Sub CopySheetAfterInput()
ThisWorkbook.Worksheets("テンプレート").Copy _
After:=ThisWorkbook.Worksheets("入力")
End Sub
実務では、単に「コピーできればよい」と考えるのではなく、コピー後のシート構成まで考えて位置を決めることが大切です。
例えば、
設定
テンプレート
入力
集計
という構成のブックで、入力用シートをテンプレートから作成するのであれば、「入力」の後ろへ追加するなど、業務上分かりやすい位置を決めておくと管理しやすくなります。
シート数が増えてから人が並び替える設計にするよりも、VBA側で追加位置まで制御しておく方が運用ミスを減らせます。
CopyメソッドとSheets.Addでは、新しいシートを作成する目的が異なります。空白シートの追加と既存シートの複製をどのように使い分けるか確認したい場合は、「【VBA】シートコピーを自動化する方法|Add・Copyメソッドの違いと使い方を徹底解説」もあわせて確認してみてください。
✅ VBAでコピー元シートを変数にして安全に追加する
短いマクロであれば、ThisWorkbook.Worksheets("テンプレート")をそのまま記述しても問題ありません。しかし、処理が増えてくると同じシート指定を何度も書くことになり、シート名の変更や処理追加に弱いコードになりがちです。
特に実務では、作成した本人とは別の担当者が後からコードを修正するケースもあります。そのとき、「どのシートをコピー元として扱っているのか」が分かりにくいコードは、確認だけでも時間がかかります。シートを変数へ格納して役割を明確にしておくと、コードの意図を追いやすくなり、後から処理を追加するときにも扱いやすくなります。
・コピー元とコピー先をWorksheet型で管理する
実務を意識する場合は、コピー元とコピー先をWorksheet型の変数へ格納してから処理する方法があります。
Sub CopyTemplateSheet()
Dim sourceSheet As Worksheet
Dim destinationSheet As Worksheet
'コピー元とコピー位置の基準になるシートを取得
Set sourceSheet = ThisWorkbook.Worksheets("テンプレート")
Set destinationSheet = ThisWorkbook.Worksheets("集計")
'テンプレートを集計シートの後ろへコピー
sourceSheet.Copy After:=destinationSheet
End Sub
この書き方では、
sourceSheet:コピーする元シートdestinationSheet:コピー位置の基準となるシート
という役割が変数名から判断できます。
直接記述する方法と比べるとコードは少し長くなりますが、後から処理が増えたときに読みやすいのがメリットです。
例えばコピー前にコピー元シートを確認したり、コピー後に別の処理を実行したりする場合でも、sourceSheetという変数をそのまま利用できます。
「コードを短くすること」よりも、何を対象として処理しているのかが分かることを優先した方が、長期間利用する業務マクロでは保守しやすくなります。
・シート名を直接何度も指定しない理由
例えば、次のようなコードでも処理自体は実行できます。
ThisWorkbook.Worksheets("テンプレート").Copy _
After:=ThisWorkbook.Worksheets("集計")
1回だけコピーする処理なら、むしろこの書き方の方が簡潔です。
一方、同じシートを後続処理でも何度も利用するのであれば、
Set sourceSheet = ThisWorkbook.Worksheets("テンプレート")
のように最初にオブジェクトを取得しておくことで、コード内で同じ指定を繰り返さずに済みます。
実務では「すべて変数にすればよい」というわけではありません。
一度しか使わない対象なら直接指定し、複数の処理で利用する対象なら変数化するというように、処理規模に応じて使い分けるとコードが必要以上に複雑になりません。
✅ VBAでコピーした新しいシートを取得する
シートをコピーするだけならCopyメソッドを実行すれば完了します。しかし実際の業務では、コピー直後にシート名を変更したり、特定のセルへ日付や担当者名を書き込んだりすることが多くあります。このときコピー元シートとコピー後のシートを混同すると、テンプレート側を書き換えてしまうなどの事故につながります。
特にコピー後の処理が増えるほど、「現在どのシートを操作しているのか」を明確にすることが重要です。そのため、コピー処理だけで終わらず、コピーによって作成されたシートをオブジェクトとして取得するところまで考えておくと、後続処理を安全に組み立てやすくなります。
・コピー直後のシートをWorksheet変数へ格納する
例えば、「テンプレート」シートをコピーした後、そのコピーをnewSheetとして扱う場合は次のようにできます。
Sub CopyAndGetNewSheet()
Dim sourceSheet As Worksheet
Dim newSheet As Worksheet
Set sourceSheet = ThisWorkbook.Worksheets("テンプレート")
'コピー元の直後へシートを複製
sourceSheet.Copy After:=sourceSheet
'コピーによって作成されたシートを取得
Set newSheet = sourceSheet.Next
End Sub
今回はコピー元の直後へシートを作成しているため、sourceSheet.Nextから新しく作成されたシートを取得できます。
このようにコピーしたシートをnewSheetへ格納しておけば、後続処理ではコピー元とコピー先を明確に区別できます。
例えば、
newSheet.Name = "4月"
とすれば、コピー元の「テンプレート」を変更せず、作成されたコピー側だけに新しい名前を設定できます。
ただし、実務ではシート名の重複やコピー元シートが存在しないケースも考える必要があります。
特に月次帳票のようにマクロを何度も実行する可能性がある処理では、すでに同じ名前のシートが存在している状態で名前を変更するとエラーになります。
そのため、コピー処理そのものだけでなく、「コピー前の確認」と「コピー後の管理」をセットで設計することが重要です。
✅ VBAでコピーしたシートの名前を変更する
シートをコピーする処理では、コピーできた時点で完成と考えてしまいがちですが、実務ではコピー後のシートをどのように管理するかが重要です。Excelはコピーしたシートに自動的な名前を付けますが、そのままでは何のために作成されたシートなのか分かりにくくなります。月別や担当者別のシートを作成する場合は、コピー直後に目的に合った名前へ変更しておく方が管理しやすくなります。
ただし、すでに同じ名前のシートが存在していると、Nameプロパティによる変更時にエラーが発生します。コピー処理を繰り返し実行する可能性がある場合は、名前の重複まで考慮して設計しておくことが大切です。
・コピーしたシートだけをNameプロパティで変更する
前半で取得したnewSheetを利用すれば、コピーしたシートだけを対象として名前を変更できます。
Sub CopyAndRenameSheet()
Dim sourceSheet As Worksheet
Dim newSheet As Worksheet
Set sourceSheet = ThisWorkbook.Worksheets("テンプレート")
'テンプレートの直後へシートをコピー
sourceSheet.Copy After:=sourceSheet
'コピーによって作成されたシートを取得
Set newSheet = sourceSheet.Next
'コピーしたシートの名前を変更
newSheet.Name = "4月"
End Sub
処理の流れは次のとおりです。
sourceSheetへ「テンプレート」シートを格納するsourceSheet.Copyでテンプレートを複製するsourceSheet.Nextでコピーされたシートを取得するnewSheet.Nameでコピー側の名前を変更する
ここでnewSheetを使用する理由は、コピー元とコピー後のシートを明確に区別するためです。
コピー後にセルへの書き込みや書式変更などを追加する場合も、
newSheet.Range("B2").Value = Date
のように記述できます。
どのシートへ値を書き込んでいるのかがコードから判断しやすいため、後から処理内容を確認するときにも役立ちます。
・同じシート名が存在すると名前変更でエラーになる
例えば、すでに「4月」というシートが存在している状態で、
newSheet.Name = "4月"
を実行することはできません。
月次処理では、一度マクロを実行した後に利用者が誤ってもう一度ボタンを押すことも考えられます。
そのため、業務で繰り返し使用するマクロでは、
「コピーできるか」だけではなく、「コピーしてよい状態か」
を確認することが重要です。
シートの存在確認を行ってから作成する方法を採用すれば、同名シートによるエラーだけでなく、意図しないシートの重複作成も防ぎやすくなります。
既存シートをコピーするのではなく、Sheets.Addで新しいシートを作成してから名前を設定したい場合は、「【VBA】シートを追加して名前を付ける方法|Sheets.Add・Nameプロパティの実務活用」で基本的な作成方法を解説しています。
✅ VBAでシート名の重複を確認してからコピーする
シートコピーの自動化で起きやすい失敗の一つが、同じ処理を複数回実行してしまうことです。特にボタンからマクロを実行する業務ファイルでは、処理が終わったことに気付かず、利用者が再度ボタンを押すことがあります。コピー後の名前変更だけを考えたコードでは、同じシート名が存在した時点でエラーになり、処理が途中で停止します。
また、自動的に別名を付けて処理を続ける設計が必ずしも正しいとは限りません。月次帳票などでは、同じ月のシートを2枚作成しないことの方が重要だからです。実務では、コピーする前に対象シートの存在を確認し、必要な場合だけ処理を進める設計が安全です。
・既存シートを確認して不要なコピーを防ぐ
例えば、「4月」シートが存在しない場合だけテンプレートをコピーするのであれば、次のようなコードにできます。
Sub CopyTemplateSafely()
Dim sourceSheet As Worksheet
Dim checkSheet As Worksheet
Dim newSheet As Worksheet
Dim newSheetName As String
Dim sheetExists As Boolean
newSheetName = "4月"
Set sourceSheet = ThisWorkbook.Worksheets("テンプレート")
'同じ名前のシートが存在するか確認
For Each checkSheet In ThisWorkbook.Worksheets
If checkSheet.Name = newSheetName Then
sheetExists = True
Exit For
End If
Next checkSheet
'すでに存在する場合はコピーしない
If sheetExists Then
MsgBox newSheetName & " シートはすでに存在します。"
Exit Sub
End If
'テンプレートをコピー
sourceSheet.Copy After:=sourceSheet
'作成されたシートを取得して名前を設定
Set newSheet = sourceSheet.Next
newSheet.Name = newSheetName
End Sub
少しコードは長くなりますが、処理の目的は明確です。
まずnewSheetNameへ作成予定のシート名を設定し、For Eachで現在のブックに同名シートがないか確認しています。
同じ名前が見つかった場合は、
Exit Sub
によってコピー処理そのものを終了します。
存在しなければテンプレートをコピーし、作成されたシートへ予定していた名前を設定します。
この方法のメリットは、エラーが起きてから対処するのではなく、問題になる状態を事前に確認できることです。
また、newSheetNameを変数として分離しているため、後から「5月」「6月」などへ変更したり、別の処理からシート名を受け取ったりするときにも流用しやすくなります。
なお、シートの存在確認そのものを共通処理として利用する場合は、専用のFunctionとして分離する方法もあります。
ただし、小規模なマクロで一度しか確認しないのであれば、無理に処理を細分化する必要はありません。
コードの再利用性だけを追求するのではなく、処理規模に対して読みやすい構成になっているかも判断基準にするとよいでしょう。
シートの存在確認を利用して「対象シートがなければ新しく作成する」処理にしたい場合は、「【VBA】シートがなければ作成する方法|存在確認して安全に追加する実務コード」も参考になります。コピーではなく新規追加が必要な処理では、こちらの方法と使い分けると安全です。
✅ VBAでシートをコピーするときに注意したいポイント
Copyメソッド自体は短いコードで使用できますが、業務ファイルではコピーできることだけを確認して終わらせない方が安全です。テンプレートの名前が変更されたり、コピー先として想定していたシートが削除されたりすると、正常に動いていたマクロでもエラーになることがあります。
また、ActiveSheetやSheets(1)のように現在の状態やシート位置へ依存するコードは、ブック構成が変わったときに別のシートを処理する危険があります。作成時点では問題がなくても、数か月後の運用変更によって不具合が発生するケースは珍しくありません。そのため、シートコピーでは対象ブック・コピー元・コピー後のシートをできるだけ明確に扱うことが重要です。
・ActiveSheetへの依存をできるだけ避ける
例えば、次のようなコードは簡単に記述できます。
ActiveSheet.Copy After:=ActiveSheet
しかし、このコードでは実行時に選択されているシートがコピー対象になります。
利用者が別のシートを開いた状態でマクロを実行すると、想定とは異なるシートが複製される可能性があります。
コピー対象があらかじめ決まっている業務であれば、
Set sourceSheet = ThisWorkbook.Worksheets("テンプレート")
のように対象を明示した方が安全です。
同じ理由から、
Worksheets(1)
のようなインデックス番号だけに依存するコードにも注意が必要です。
シートの並び順が変更されれば、Worksheets(1)が示すシートも変わります。
「テンプレートをコピーする」という仕様が決まっているのであれば、コード上でもその意図が分かる指定にしておく方が保守しやすくなります。
・コピー元のテンプレートを直接変更しない
テンプレート方式で帳票を作成する場合は、原本となるシートを変更しないことも重要です。
例えば、コピー後に日付を入力する場合は、
sourceSheet.Range("B2").Value = Date
ではなく、
newSheet.Range("B2").Value = Date
とします。
sourceSheetを書き換えてしまうと、次回コピーするときの原本自体が変更された状態になります。
コピー元とコピー後を、
sourceSheet → 原本
newSheet → 今回作成した業務用シート
という役割で分離しておけば、後続処理でも判断しやすくなります。
コピーする位置を固定シートの前後ではなく、常にブック内の最後へ統一したい場合は、「【VBA】最後のシートの後ろにコピーする方法|基本構文から自動命名・応用まで完全ガイド」で末尾へのコピー方法を詳しく解説しています。
✅ VBAのシートコピーを実務で活用する場面
シートコピーは単純な複製機能と思われがちですが、実務ではテンプレートから帳票を作成する仕組みと組み合わせることで特に効果を発揮します。ただし、何でもコピーで作成すればよいわけではありません。空白シートが必要なだけなら、既存シートを複製する必要はないためです。
一方、セルの配置や書式、数式、印刷用レイアウトなどを毎回同じ状態から始めたい場合は、テンプレートをコピーする方法が管理しやすくなります。処理方法を選ぶときは、「新しいシートが必要なのか」「既存の構成を引き継ぎたいのか」を分けて考えることがポイントです。
・月次帳票や担当者別シートの作成に活用する
Copyメソッドが活用しやすいのは、例えば次のようなケースです。
- 月ごとに同じ形式の集計シートを作成する
- 担当者ごとに同じ入力フォーマットを用意する
- 部署ごとの報告シートをテンプレートから作成する
- 同じ数式や書式を持つ帳票を複製する
このような処理では、空白シートを追加してからVBAですべてのレイアウトを再現するより、完成したテンプレートをコピーする方がコードを簡潔にできる場合があります。
例えば、
テンプレート
↓ Copy
4月
↓ Copy
5月
↓ Copy
6月
という運用にすれば、レイアウト変更が発生した場合もテンプレート側を修正することで管理しやすくなります。
ただし、すでに作成済みの「4月」「5月」などのシートまでテンプレート変更に合わせて自動更新されるわけではありません。
コピーした時点で別のワークシートになるため、テンプレートの変更を過去シートへ反映させる必要がある業務では、別途更新方法を検討する必要があります。
1枚のシートをコピーするのではなく、複数の新しいシートをまとめて作成したい場合は、「【VBA】複数シートを一括追加する方法|複数枚の作成と実務での使い分け」で、一括作成する方法も確認できます。
・大量のシートを作る場合は設計自体も見直す
担当者や商品ごとに数枚のシートを作成する程度なら、テンプレートコピーは分かりやすい方法です。
一方で、数十枚・数百枚のシートを継続的に増やす運用では、コピー処理を増やす前にブック設計そのものを検討した方がよい場合があります。
例えば、データを1枚の一覧表へ集約し、フィルターやピボットテーブルなどで表示対象を切り替えられる業務であれば、シートを大量に複製しない方が管理しやすいケースもあります。
VBAによって自動化できるからといって、必ずしもシートを増やす設計が最適とは限りません。
「自動化できるか」だけでなく、「作成されたExcelファイルを後から人が管理しやすいか」まで考えることが、実務で長く使えるマクロを作るポイントです。
✅ まとめ:VBAのCopyメソッドでシートを安全にコピーして追加しよう
VBAではCopyメソッドを使用することで、既存のワークシートを複製して新しいシートとして追加できます。コード自体は短く書けますが、業務で利用する場合はコピー位置やコピー後のシート管理まで考えることが重要です。
特にテンプレートを利用する処理では、コピー元とコピー後のシートを明確に分けておくことで、原本を誤って変更するリスクを減らせます。また、同じ名前のシートが存在する可能性がある場合は、コピー前に確認することで処理途中のエラーや重複作成を防げます。
- 既存シートの複製には
Copyメソッドを使用する BeforeまたはAfterでコピーする位置を明確にする- コピー位置を指定しない場合の動作に注意する
- コピー元を
sourceSheetなどのWorksheet変数で管理すると役割が分かりやすい - コピー後のシートも
newSheetとして取得すると後続処理を組み立てやすい - Nameプロパティで名前を変更するときは既存シートとの重複に注意する
ActiveSheetなど現在の選択状態に依存した処理は、固定された業務ではできるだけ避ける- テンプレート方式ではコピー元を原本として維持し、変更はコピー後のシートへ行う
- 大量のシートを継続的に作成する場合は、シートコピー以外のデータ管理方法も検討する
シートコピーを自動化するときは、単にCopyメソッドを実行するだけではなく、「何を原本として、どこへコピーし、作成したシートをその後どう扱うのか」まで設計することが大切です。
コピー元とコピー後のシートを明確に管理しておけば、月次帳票や担当者別フォーマットなどにも応用しやすくなり、後から修正するときにも分かりやすいVBAコードにできます。