VBA シート 追加 削除 コピー

VBA シート 追加 削除 コピー アイキャッチ画像 マクロ・VBA

月次決算の時期になると、経理部の担当者は数百社分の個別明細シートを作成しなければならない。かつての私も、営業管理の現場で47都道府県別の報告用シートを手作業で「右クリックしてコピー」を繰り返していた時期がある。1つコピーしては名前を変え、また1つコピーしては名前を変える。この単調な作業だけで、気づけば1時間が経過していた。しかし、Excel VBAの基本的な命令を数行書くだけで、この1時間はわずか5秒に短縮できる。マクロの力を使えば、ヒューマンエラーを排除しながら、本来集中すべき分析業務に時間を割くことが可能だ。

  1. Excel VBAでシートを追加・削除・コピーする基本操作を現場目線で整理する
    1. シートを追加する基本命令とオブジェクトの指定
    2. 既存のシートをコピーする際の注意点
    3. シートを削除するコードと警告の回避
  2. 営業部で重宝する「支店別売上シート」の自動生成コード
    1. マスタリストから動的にシートを作成する手順
  3. 経理担当者が泣かされる「削除時のアラート」をスマートに回避する仕組み
    1. 特定条件に合致するシートの一括削除
    2. 削除できないシートの存在に注意
  4. 既存シートをテンプレートにして書式ごと複製する確実な方法
    1. 書式と計算式を保持したままのコピー
  5. 大量シート作成時に処理速度を落とさないための2つの工夫
    1. 画面更新の停止(ScreenUpdating)
    2. 自動再計算の停止(Calculation)
  6. インデックス番号指定とシート名指定の使い分けでバグを防ぐ
    1. 名前指定のリスクと対策
    2. インデックス番号が有効な場面
  7. 意図しない削除を防ぐための「シート存在チェック」の実装
    1. シートの存在を確認する汎用関数
  8. スプレッドシートのGoogle Apps Script(GAS)とExcel VBAの挙動の違い
    1. 追加とコピーのメソッド名の差
    2. 実行環境によるスピードの差
  9. Excel 2016からMicrosoft 365まで共通して使える安定コードの書き方
    1. 32bit版と64bit版の差異を気にする必要はない
    2. Mac版Excelでの挙動
  10. 実務の現場でよく聞かれる「これってVBAでできる?」への回答集
    1. Q1. 複数のシートを一度に選択してコピーできますか?
    2. Q2. シートをコピーしたときに、マクロボタンも一緒にコピーされますか?
    3. Q3. 隠れている(非表示の)シートをコピーすることはできますか?
  11. 現場の自動化を一歩進めるための翌営業日からのアクション
    1. 関連記事

Excel VBAでシートを追加・削除・コピーする基本操作を現場目線で整理する

実務でマクロを組む際、最も頻繁に登場するのがシートの操作だ。特に「VBA シート 追加 削除 コピー」という一連の流れは、自動化の骨格となる。基本となるコードは非常にシンプルだが、現場で「動かない」「エラーが出る」と相談を受けるコードの多くは、この基本部分の指定が曖昧なことに起因する。

シートを追加する基本命令とオブジェクトの指定

シートを追加する際の基本コードは Worksheets.Add だ。これだけで新しいワークシートが現在のシートの直前に挿入される。しかし、実務では「一番最後に追加したい」という要望が大半だろう。その場合は引数を使用して場所を指定する。

' 一番最後に追加する例
Worksheets.Add After:=Worksheets(Worksheets.Count)

ここで Worksheets.Count を使うのが実務の定番だ。これにより、シートが何枚あっても常に末尾へ追加される。筆者が社内研修で教えていると、初心者の多くは Worksheets.Add だけを覚えてしまい、変な場所にシートが挟まって集計がズレるという失敗を経験する。追加場所の制御は、自動化の第一歩といえる。

VBA シート 追加 削除 コピー - シート末尾に新しいワークsheetが追加された状態
シート末尾に新しいワークsheetが追加された状態

既存のシートをコピーする際の注意点

シートのコピーは Worksheets("原本").Copy と記述する。引数を指定しない場合、新しいブックが自動で作成され、そこにシートがコピーされる。同じブック内にコピーしたい場合は、追加と同様に AfterBefore を指定しなければならない。

' 「原本」シートを末尾にコピーし、名前を「2026年6月」にする
Worksheets("原本").Copy After:=Worksheets(Worksheets.Count)
ActiveSheet.Name = "2026年6月"

実務でよく見かけるのは、コピー直後のシートが ActiveSheet(現在選択されているシート)になる性質を利用した名前の変更だ。ただし、大量のシートをコピーする場合、この性質を過信すると予期せぬ動作を招くことがある。確実を期すなら、オブジェクト変数に格納する手法が中級者への道となる。

シートを削除するコードと警告の回避

シートの削除は Worksheets("削除用").Delete で実行できる。しかし、これを実行するとExcelから「このシートは完全に削除されます。続けますか?」という確認メッセージが表示される。マクロで100枚のシートを削除する際、100回クリックするのは自動化とは呼べない。これを回避するのが Application.DisplayAlerts プロパティだ。

Application.DisplayAlerts = False ' 警告をオフにする
Worksheets("Sheet1").Delete
Application.DisplayAlerts = True  ' 警告をオンに戻す

ポイント: 警告をオフにした後は、必ず True に戻す癖をつけよう。戻し忘れると、保存せずにファイルを閉じる際などの重要な警告まで表示されなくなり、取り返しのつかないデータ損失を招く恐れがある。

営業部で重宝する「支店別売上シート」の自動生成コード

ある製造業の営業部では、毎月各支店から送られてくる売上データを集計し、支店ごとの報告用シートを作成していた。対象となるのは全国30拠点の支店だ。これを手作業で行うと、シート名の入力ミスや、コピー元の書式崩れが頻発する。こうした場面でこそ、VBAのループ処理とシート操作の組み合わせが真価を発揮する。

マスタリストから動的にシートを作成する手順

「設定」シートのA列に支店名リスト(A1:札幌, A2:仙台, A3:東京…)がある場合、そのリストを読み取って次々にシートを追加していく。実務では単なる追加ではなく、フォーマットが決まった「テンプレート」シートをコピーするのが一般的だ。

  1. テンプレートとなるシートを作成し、デザインを整える
  2. マスタリストの最終行を取得する
  3. For〜Next構文でリストの数だけループを回す
  4. テンプレートをコピーし、リストから取得した支店名をシート名に設定する
Sub 支店別シート作成()
    Dim i As Long
    Dim lastRow As Long
    Dim branchName As String
    
    ' 設定シートから最終行を取得
    lastRow = Worksheets("設定").Cells(Rows.Count, 1).End(xlUp).Row
    
    For i = 2 To lastRow ' 1行目がヘッダーと想定
        branchName = Worksheets("設定").Cells(i, 1).Value
        
        ' テンプレートを末尾にコピー
        Worksheets("テンプレート").Copy After:=Worksheets(Worksheets.Count)
        
        ' コピーされたシート(ActiveSheet)に名前をつける
        On Error Resume Next ' 同名シートがある場合のエラー対策
        ActiveSheet.Name = branchName
        If Err.Number <> 0 Then
            MsgBox branchName & "の作成に失敗しました。シート名が重複していないか確認してください。"
            Err.Clear
        End If
        On Error GoTo 0
    Next i
End Sub
VBA シート 追加 削除 コピー - マスタリストに基づき複数の支店別シートが自動生成される様子
マスタリストに基づき複数の支店別シートが自動生成される様子

筆者の経験では、このコードに「既にシートが存在する場合の処理」を組み込んでおかないと、二度目にマクロを実行した際にエラーで止まってしまう。初心者がつまずきやすいポイントは、この「二回目以降の動作」を考慮していない点にある。実務で使用するツールは、何度実行しても安全に動く頑健さが求められる。

経理担当者が泣かされる「削除時のアラート」をスマートに回避する仕組み

経理部の月次締め作業では、一時的に計算用シートを作成し、最終的な数値を確定させた後にそのシートを破棄するワークフローが多い。ある商社の経理部では、複雑な配賦計算のために10枚以上の計算用シートを作成していたが、作業終了後にそれらを一枚ずつ手で削除していたという。

特定条件に合致するシートの一括削除

「TEMP_」で始まる名前のシートだけをすべて削除したい、というニーズは非常に多い。これには For Each 文を使い、すべてのシートを順番にチェックしていく手法が適している。

Sub 計算用シートの一括削除()
    Dim ws As Worksheet
    
    ' 警告を非表示にする(これを忘れると何度もクリックが必要になる)
    Application.DisplayAlerts = False
    
    For Each ws In ThisWorkbook.Worksheets
        ' シート名が "TEMP_" で始まる場合
        If ws.Name Like "TEMP_*" Then
            ws.Delete
        End If
    Next ws
    
    Application.DisplayAlerts = True
    MsgBox "計算用シートの削除が完了しました。"
End Sub

経理の現場では、この設定を忘れて集計がずれるケースをよく見かけます。例えば、削除すべき古いデータシートが残ったまま新しい計算を行ってしまい、合算値が二重計上されるといったトラブルだ。VBAによる強制的な「クリーンアップ」は、人為的なミスを物理的に不可能にするために不可欠な工程といえる。

VBA シート 追加 削除 コピー - 特定の接頭辞を持つシートが一覧から消去された後の画面
特定の接頭辞を持つシートが一覧から消去された後の画面

削除できないシートの存在に注意

実務でこのマクロを走らせる際、注意が必要なのは「ブックに最低1枚の可視シートが必要」というExcelの仕様だ。すべてのシートを削除しようとするコードを書くと、最後の1枚を消そうとした瞬間に実行時エラーが発生する。筆者も新人の頃、条件分岐を誤って全シートを消去対象にしてしまい、エラーメッセージの前で立ち尽くした経験がある。必ず「マスタ」や「メニュー」といった消さないシートを保護するロジックを入れておくべきだ。

既存シートをテンプレートにして書式ごと複製する確実な方法

単に新しいシートを追加するのと、既存のシートをコピーするのでは、実務上の意味合いが大きく異なる。追加(Add)は真っ白なキャンバスを作る作業だが、コピー(Copy)は印鑑の枠や計算式、条件付き書式が含まれた「型」を複製する作業だ。

書式と計算式を保持したままのコピー

Worksheets("Template").Copy を使う最大のメリットは、印刷設定やセルの幅まで完全に引き継げる点にある。総務部で使う備品管理表や、プロジェクトごとの工数管理シートなど、デザインが固定されているものは必ずコピーを使用しよう。ここで、引数の BeforeAfter の違いを明確にしておきたい。

引数 記述例 挿入位置
Before Copy Before:=Worksheets(1) 指定したシートの「前」に挿入(一番左になる)
After Copy After:=Worksheets(Worksheets.Count) 指定したシートの「後」に挿入(一番右になる)

多くの場合、最新のシートは右側に追加していくのが自然だ。しかし、履歴を重視する現場では「常に左側に新しい月を置きたい」という要望もある。その場合は Before:=Worksheets(1) と記述すればよい。このように、現場の運用ルールに合わせて位置を1行変えるだけで、使い勝手は格段に向上する。

VBA シート 追加 削除 コピー - テンプレートシートから書式を維持してコピーされた新しいシート
テンプレートシートから書式を維持してコピーされた新しいシート

注意点: 非常に複雑な条件付き書式や、大量のオブジェクト(図形)が含まれるシートを数百枚コピーすると、ブックのサイズが肥大化し、Excelの動作が極端に重くなることがある。必要に応じて、コピー後に「値貼り付け」を行い、数式を解除する処理を検討しよう。

大量シート作成時に処理速度を落とさないための2つの工夫

「VBAでシートを追加・コピーするマクロを書いたが、実行中に画面がチカチカして時間がかかる」という相談をよく受ける。特に100枚単位でシートを操作する場合、Excelは1枚操作するたびに画面を描画し直し、再計算を試みる。これがボトルネックとなる。

画面更新の停止(ScreenUpdating)

最も効果的なのは Application.ScreenUpdating = False だ。これをコードの冒頭に入れるだけで、処理速度は数倍から、時には10倍以上に跳ね上がる。画面の描画を止めることで、CPUのパワーをすべてシート操作に割り振ることができるからだ。

自動再計算の停止(Calculation)

コピー元のシートに重い数式(VLOOKUPやSUMIFSなど)が大量に入っている場合、コピーのたびにブック全体が再計算されてしまう。これを防ぐために、処理中は計算方法を「手動」に切り替えるのが定石だ。

Sub 高速シート操作()
    On Error GoTo ErrorHandler
    ' 1. 高速化の設定
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual
    
    ' --- ここにシート追加・コピーの処理を書く ---
    
CleanUp:
    ' 2. 設定を必ず元に戻す
    Application.Calculation = xlCalculationAutomatic
    Application.ScreenUpdating = True
    Exit Sub

ErrorHandler:
    MsgBox "エラーが発生しました: " & Err.Description
    Resume CleanUp
End Sub

実務で使うプロのコードには、必ずと言っていいほどこの「おまじない」が含まれている。研修でこの設定を教えると、受講生からは「自分のマクロが壊れたのかと思うほど速くなった」と驚きの声が上がる。地味な設定だが、ユーザー体験を左右する重要なテクニックだ。

インデックス番号指定とシート名指定の使い分けでバグを防ぐ

VBAでシートを指定する方法には、大きく分けて「名前で指定」する方法と「インデックス番号で指定」する方法の2種類がある。初心者は名前指定を多用しがちだが、ここには大きな落とし穴がある。

名前指定のリスクと対策

Worksheets("売上データ") という書き方は、コードを読んだときに意味が分かりやすい。しかし、ユーザーがシート名を「売上データ 」(最後にスペースが入った)と変更してしまった瞬間に、マクロは「そんなシートはありません」とエラーを吐いて停止する。これを回避するためには、VBAエディタ上で設定できる「オブジェクト名(コード名)」を使用するのが最も堅牢だ。

筆者の経験では、大規模なシステムを組む際は必ずオブジェクト名を使う。シート名が「4月」から「April」に変わっても、コードを1箇所も修正せずに済むからだ。これは保守コストを劇的に下げる重要な設計判断だ。

インデックス番号が有効な場面

一方で、Worksheets(1) のように番号で指定するのが有効なケースもある。それは「中身が何であれ、一番左にあるシートを処理したい」という場合だ。例えば、複数のブックから一番左のシートだけを収集して集計するような汎用ツールを作る際には、名前を特定できないためインデックス番号が必須となる。

VBA シート 追加 削除 コピー - VBEのプロパティウィンドウでシートのオブジェクト名を確認する画面
VBEのプロパティウィンドウでシートのオブジェクト名を確認する画面

ただし、インデックス番号はシートをドラッグして並べ替えると変わってしまう。この不安定さを理解した上で、用途に合わせて使い分ける必要がある。

意図しない削除を防ぐための「シート存在チェック」の実装

シートを削除したり追加したりする際、最も多いエラーが「削除しようとしたシートが存在しない」あるいは「追加しようとしたシート名が既に使われている」というものだ。これらを防ぐためには、実行前にシートの存在を確認する自作関数(Function)を用意しておくと便利だ。

シートの存在を確認する汎用関数

以下の関数を標準モジュールに置いておけば、どこからでも呼び出してチェックができる。これは、私が長年の開発経験から「どのようなプロジェクトでも必ず入れる」と決めているパーツの一つだ。

Function CheckSheetExist(ByVal sheetName As String) As Boolean
    Dim ws As Worksheet
    On Error Resume Next
    Set ws = ThisWorkbook.Worksheets(sheetName)
    On Error GoTo 0
    
    If Not ws Is Nothing Then
        CheckSheetExist = True
    Else
        CheckSheetExist = False
    End If
End Function

これを利用すれば、シート操作の前に安全確認を挟める。例えば「もしシートがあれば削除し、その後に新しく作る」といった処理が可能になる。あるIT企業の保守部門では、この1ステップを挟まなかったために、重要な履歴シートを誤って上書き削除してしまう事故が起きた。自動化において、事前のチェックは「しすぎる」ということはない。

Sub 安全なシート追加()
    Dim newName As String
    newName = "2026年実績"
    
    If CheckSheetExist(newName) Then
        If MsgBox("既にシートがあります。削除して再作成しますか?", vbYesNo) = vbYes Then
            Application.DisplayAlerts = False
            Worksheets(newName).Delete
            Application.DisplayAlerts = True
        Else
            Exit Sub ' 処理を中断
        End If
    End If
    
    Worksheets.Add.Name = newName
End Sub

スプレッドシートのGoogle Apps Script(GAS)とExcel VBAの挙動の違い

近年、Googleスプレッドシートの普及に伴い、Excel VBAとGAS(Google Apps Script)を併用する場面が増えている。両者は似ているようで、シート操作の挙動には明確な差がある。

追加とコピーのメソッド名の差

Excel VBAでは AddCopy を使うが、GASでは insertSheet()copyTo() を使用する。特に大きく異なるのは、コピー後の「返り値」だ。VBAの Copy は何も返さない(コピーされたシートが ActiveSheet になるだけ)のに対し、GASの copyTo() はコピーされた新しいシートのオブジェクトを返す。そのため、GASの方が「コピーしたシートの名前を変える」といった操作をスマートに記述できる。

実行環境によるスピードの差

Excel VBAはローカルPCのメモリを使用するため、100枚のシート追加も一瞬で行える。一方、GASはクラウド上のサーバーで実行されるため、シートの追加・削除といったAPIリクエストを伴う操作は非常に低速だ。大量のシートを扱う場合は、依然としてExcel VBAに優位性があると感じる。

あるスタートアップ企業では、当初すべてをGASで自動化しようとしたが、100シートの作成に数分かかることが判明し、最終的にExcel VBAに切り替えた事例がある。適切なツール選択も、実務家としての重要なスキルだ。

Excel 2016からMicrosoft 365まで共通して使える安定コードの書き方

Excelのバージョンは日々進化しているが、シート操作の基本オブジェクトである Worksheets に関しては、ここ10年以上大きな破壊的変更はない。そのため、一度書いたコードは長く使い続けられる資産となる。Microsoft公式: Worksheets.Add メソッドの仕様を見ても、基本的な引数は変わっていない。

32bit版と64bit版の差異を気にする必要はない

VBAには32bitと64bitの差異によるAPI宣言の書き換え問題(PtrSafeなど)があるが、シートの追加・削除・コピーといった純粋なExcel内部の操作に関しては、これを気にする必要は一切ない。どのOS、どのビット数であっても共通のコードで動作する。これは、作成したツールを社内の他部署へ配布する際に非常に強力なメリットとなる。

Mac版Excelでの挙動

ただし、Mac版のExcelでVBAを動かす場合は注意が必要だ。画面更新の停止(ScreenUpdating)がWindows版ほど劇的に効かなかったり、シート削除時の確認ダイアログの挙動が微妙に異なったりすることがある。社内にMacユーザーがいる場合は、必ず実機でテストを行うべきだ。筆者の経験では、Windowsで完璧に動くシート操作マクロが、Macではファイルパスの指定や警告表示で止まるケースを何度も見てきた。

実務の現場でよく聞かれる「これってVBAでできる?」への回答集

実務でVBAを使っていると、周囲から「こんなこともできるのか」と質問攻めに合う。シート操作に関連して、よくある質問を整理した。

Q1. 複数のシートを一度に選択してコピーできますか?

可能だ。Worksheets(Array("Sheet1", "Sheet2")).Copy のように、Array関数を使ってシート名を指定すれば、複数のシートを一括で新しいブックに書き出すことができる。特定のシート群をパッケージ化して他社に送る際に非常に便利だ。

Q2. シートをコピーしたときに、マクロボタンも一緒にコピーされますか?

「フォームコントロール」のボタンであればコピーされる。しかし、「ActiveXコントロール」のボタンや、シートモジュールに書かれたイベントコード(Worksheet_Changeなど)は、コピーのされ方によって挙動が変わる。確実にコピーしたいなら、シート全体をコピーするのが正解だ。

Q3. 隠れている(非表示の)シートをコピーすることはできますか?

非表示のシートも Copy メソッドでコピー可能だ。コピーされた直後のシートも「非表示」のままなので、表示させるには Visible = xlSheetVisible を実行する必要がある。設定用シートを隠しておき、必要なときだけテンプレートとして呼び出す手法は、ユーザーに中身をいじられたくない場合に有効なテクニックだ。

VBA シート 追加 削除 コピー - 非表示のテンプレートシートをマクロで呼び出している様子
非表示のテンプレートシートをマクロで呼び出している様子

現場の自動化を一歩進めるための翌営業日からのアクション

VBAの学習において、最も重要なのは「理論」ではなく「実践」だ。本稿で紹介した Worksheets.AddDeleteCopy は、単体では小さな部品に過ぎない。しかし、これらを For Next ループや If 条件分岐と組み合わせることで、今まで何時間もかけていた苦行を瞬時に終わらせる魔法に変わる。

  • まずは、空のブックで Worksheets.Add を実行し、末尾に追加される快感を味わうこと
  • 次に、警告停止(DisplayAlerts = False)の効果を、シート削除を通して確認すること
  • そして、自分が毎月手作業で行っている「シートの量産」をコード化してみること

筆者が初めてマクロでシートの自動作成に成功したとき、画面上をシートが次々と流れていく様子を見て、背中が震えるような感動を覚えた。その瞬間から、私の仕事は「作業」ではなく「創造」に変わった。明日の業務で、もしあなたが「右クリック、コピー、名前変更」の操作を3回以上繰り返している自分に気づいたら、そこが自動化のチャンスだ。まずは =Worksheets.Add と打つところから始めてみよう。その一歩が、あなたの働き方を根底から変えることになるだろう。

コメント

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