TL;DR —
Worksheets.Addは 作成したばかりのシートを戻り値として返します。その戻り値をSet ws = Worksheets.Add(...)で受け取れば、どれが新しいシートかを二度と当てずっぽうで探さなくて 済みます。誰もがつまずくのは位置と名前の二つです。引数なしのWorksheets.Addはシートをアクティブ シートの 左 に落とし(末尾ではありません)、名前はAddの呼び出しの中では渡せません —.Nameを後から設定するのですが、そこで重複・空白・長すぎる名前は実行時エラー 1004 を投げます。
Sub AddMonthSheet()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets.Add(After:=Worksheets(Worksheets.Count))
ws.Name = "Sep 2026" ' 31 文字以内・一意・: \ / ? * [ ] を含まない
End Sub
Worksheets.Add は、ホーム ▸ 挿入 ▸ シートの挿入 と、タブ横の小さな + ボタンのコード版です。
レポート系のマクロが最初にやることの一つであり、毎回きまって同じ二か所で失敗します — シートが予想し
ない場所に現れるか、リネームの行が吹き飛ぶかです。どちらの問題も、Add を「シートを探しに行かせるコ
マンド」ではなく「完成したシートを 手渡してくれる ファクトリー」として捉えた瞬間に消えます。
この記事で学べること
- 考え方の軸 —
Addは新しいシートを返すので、それを受け取ってActiveSheetに頼るのをやめる - ほとんどのバグを防ぐ唯一のルール — 戻り値を
Worksheet型の変数に代入する - なぜ引数なしの
Addはシートを左に落とすのか、そしてBeforeとAfterでどう直すのか - なぜ
Addの中で名前を付けられないのか、そして.Nameが 1004 を投げるルール - すでに存在するときだけ追加しない方法
考え方の軸:Add はシートを手渡す
Worksheets.Add は、投げっぱなしのコマンドではありません。シートを作成し、それへの参照を返す 関数で
す。最も多い間違いは、その参照を捨ててしまうことです。
Worksheets.Add ' 新しいシートが作られ...そして見失われる
Worksheets(Worksheets.Count).Name = "Data" ' どこへ行ったか当てずっぽう
二行目は当てずっぽうです。新しいシートが末尾にあると決めてかかっていますが、既定ではそうならないので、 間違ったタブをリネームします。その先のすべて — 見出しの書き込み、書式設定、数式の追加 — が、運任せに 選ばれたシートを狙うことになります。代わりに戻り値を受け取れば、当てずっぽうは永遠になくなります。
Dim ws As Worksheet
Set ws = Worksheets.Add
ws.Name = "Data" ' これは紛れもなく、いま作ったシートそのもの
いったん ws が本物のオブジェクトを保持すれば、位置は 正しさ の観点では問題でなくなります — シート
をどこに置こうと、コードは正しいシートと会話し続けます。
最も大事なルール:戻り値を代入する
信頼できるシート追加ルーチンは、どれも同じ形で始まります — Set ws = Worksheets.Add(...)。これは、バ
グのカテゴリを丸ごと取り除くルールです。もろい代替案は二つとも、ごく普通の条件で壊れるからです。
AddのあとのActiveSheetは たいてい 新しいシートを指します — が、イベントやCalculate、ある いは別の行が先にフォーカスを動かしていれば、そうはなりません。慣習であって、保証ではありません。Sheets(Sheets.Count)は新しいシートが末尾にあると決めてかかりますが、それが真なのは、そこに追加し た場合だけです。
戻り値は、シートがどこに着地しようと、次に何が走ろうと、常に、即座に正しい唯一の参照です。「シートを 追加する」と「シートを手元に握る」を、分けられない一つのステップとして扱ってください。
位置決め:Before、After、そしてなぜ既定は左に落ちるのか
Worksheets.Add は Before:= と After:= の引数を取ります — その前に挿入するシート、あるいは後ろに
挿入するシートです。渡すのは多くても一つ。どちらも 渡さないと、Excel は新しいシートを アクティブシ
ートのすぐ前 に挿入します。これは初回にほぼ全員を驚かせます — 人は「末尾」を期待するのに、タブはブッ
クの真ん中に現れるのです。
末尾に追加するには — 実際にほとんどのマクロが望む位置です — After で最後のシートに錨を下ろします。
Set ws = Worksheets.Add(After:=Worksheets(Worksheets.Count)) ' 常に末尾
Set ws = Worksheets.Add(Before:=Worksheets(1)) ' 常に先頭
Worksheets(Worksheets.Count) は「最後のワークシート」を表す定番の書き方です。数えているのは ワークシ
ート であって全シートではない点に注意してください — ブックがグラフシートも持っていれば、Sheets.Count
と Worksheets.Count は食い違います。迷ったら明示的に位置を指定しましょう。人が読むコードで、アクティ
ブシートの左という既定に頼ってはいけません。
命名こそ Add がクラッシュする場所
Add に Name 引数はありません。シートを作成し、それから受け取ったオブジェクトに .Name を設定しま
す。実行時エラー 1004 が棲んでいるのはこの二段目です。Excel はシート名に厳格なルールを課すからで — しか
もそのルールは、新品のシートに名前を付けるときも、古いシートをリネームするときも 同じ です。
- 31 文字まで
- ブック内で 一意 でなければならない(大文字小文字は区別しない) — 重複が一番多いクラッシュ原因
- 空白にできない
: \ / ? * [ ]を 含められない
どれか一つでも破ると .Name = ... は 1004 を投げます。最も多い引き金は、すでに一度 "Data" を作った
マクロを再実行することです — 二回目の実行で衝突します。作成とリネームでルールが同一なので、名前を一か
所で守っておく価値があります。
Function SafeName(nm As String) As String
nm = Left$(nm, 31)
Dim bad As Variant, ch As Variant
For Each ch In Array(":", "\", "/", "?", "*", "[", "]")
nm = Replace(nm, ch, "-")
Next ch
SafeName = nm
End Function
これで長さと不正文字は片付きます。一意性は、先に確認することで扱います — それが次の節です。
すでに存在するときだけ追加しない
シートに組み込みの Exists はないので、再実行時の衝突を防ぐのはあなたの仕事です。追加する前に名前でコ
レクションを確認し、すでにあればそのシートを再利用します。
Function GetOrAddSheet(nm As String) As Worksheet
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
If StrComp(ws.Name, nm, vbTextCompare) = 0 Then
Set GetOrAddSheet = ws ' 既存のものを再利用
Exit Function
End If
Next ws
Set GetOrAddSheet = ThisWorkbook.Worksheets.Add(After:=Worksheets(Worksheets.Count))
GetOrAddSheet.Name = nm ' 自由に命名できる - 未使用だと分かっている
End Function
これは、初回は動くのにその後は永遠に 1004 を投げるマクロではなく、シート追加マクロを 冪等 に — 二度
実行しても安全に — するパターンです。判断はこうです。二回以上走るかもしれないルーチンで、Add と
.Name を盲目的に呼んではいけません。まず名前を調べ、再利用するか作成するかのどちらかにします。
ExcelMaster の活用
シートの追加は一行に見えて、三つの判断を隠しています — 戻り値を受け取る、位置を選ぶ、正当で一意な名前 を作る — そしてどれを間違えても、静かに(間違ったタブをリネーム)あるいは派手に(二回目の実行でエラー 1004)失敗します。
ExcelMaster には、望むことをそのま
ま伝えられます — 「今月の名前を付けた月次シートを末尾に追加して、すでにあれば再利用して」 — すると、
Set ws = Worksheets.Add(After:=...) の受け取りを書き、正しい場所に追加し、31 文字ルールと不正文字ルー
ルに照らして名前を整え、まずコレクションを確認して、二回目の実行がクラッシュせずシートを再利用するよう
にします。ブックとコードはあなたの手元に残ります。
よくある質問
VBA でシートを追加して名前を付けるには?
戻り値を受け取り、それに .Name を設定します — Set ws = Worksheets.Add(After:=Worksheets(Worksheets.Count))、
それから ws.Name = "Data"。Add 自体に Name 引数はありません。名前は 31 文字以内、ブック内で一意、
空白でなく、: \ / ? * [ ] を含まないこと。さもないと .Name が実行時エラー 1004 を投げます。
新しいシートが変な位置に現れるのはなぜ?
引数なしの Worksheets.Add が、末尾ではなく アクティブシートのすぐ前 にシートを挿入するからです。
Before:= か After:= で制御します。末尾に追加するなら Worksheets.Add(After:=Worksheets(Worksheets.Count))、
先頭に置くなら Worksheets.Add(Before:=Worksheets(1)) を使います。
シートの追加や命名でエラー 1004 が出るのはなぜ?
ほぼ必ず名前ルール違反で、たいていは重複です。シート名は一意でなければならないので、すでに "Data" を
作ったマクロを再実行すると二回目で衝突します。名前はさらに、31 文字以内、空白でなく、: \ / ? * [ ] を
含まないこと。追加する前にコレクションで名前を確認し、まず文字列を整えましょう。
すでに存在するときは追加しないようにするには?
Exists メソッドはないので、Worksheets コレクションをループし、StrComp(ws.Name, nm, vbTextCompare) = 0
で名前を比較します。一致すればそのシートを再利用し、なければ Add を呼んで命名します。これを
GetOrAddSheet 関数に包めば、マクロを繰り返し実行しても安全になります。
ブックのいちばん末尾にシートを追加するには?
最後のワークシートに錨を下ろします — Worksheets.Add(After:=Worksheets(Worksheets.Count))。
Worksheets(Worksheets.Count) が最後のワークシートなので、その 後ろ に挿入すれば末尾に追加されます。
Worksheets.Count の代わりに Sheets.Count を使うのは、グラフシートも意図的に数えたいときだけにしまし
ょう。
検証環境
検証環境: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-09-14。
関連ガイド: VBA シートのコピー · VBA シートの削除 · VBA Worksheets · VBA Worksheet · VBA ThisWorkbook
