TL;DR —
Worksheetsは コレクション で、その中のシートは3通りで指定します — 名前 (Worksheets("Jan"))、インデックス(Worksheets(1))、または CodeName(Sheet1)。名前は ユーザーがタブをリネームした瞬間に壊れ、インデックスは誰かがタブを新しい順にドラッグした瞬間に壊れ、 CodeName はそのどちらでも壊れません。変更できるのはあなただけだからです。コレクションをブックで限定し、 シートを 一度だけ 変数にSetし、あなたが管理するタブには CodeName を優先してください。
Sub ThreeWaysToNameASheet()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Jan") ' 名前で - タブがリネームされると壊れる
Set ws = ThisWorkbook.Worksheets(1) ' インデックスで - タブが並べ替えられると壊れる
Set ws = Sheet1 ' CodeName で - どちらでも壊れない
ws.Range("A1").Value = "Report"
End Sub
この記事で学べること
- 考え方の軸 —
Worksheetsは3通りで指定できるコレクション - 3つの参照の道具と、その中で
Worksheetsコレクションが座る位置 WorksheetsとSheets、そして実際に効いてくるグラフシートの違い- シートを名指しする3つの方法と、それぞれを正確に何が壊すか
- 静かな罠 — 動いていたマクロが、ユーザーがタブをリネームした日に死ぬ理由
- 意見 — 一度だけ、限定して
Setし、CodeName を優先する
考え方の軸:3通りで指定するコレクション
Worksheets は単一のオブジェクトではありません — ブック内のすべてのワークシートの コレクション です。
1枚のシートに何かをするには、識別子でコレクションから取り出します。VBAは3つの識別子をくれますが、それらは
同じ頑丈さではありません。
- 名前で —
Worksheets("Jan")— タブ上の文字です。読みやすく、最も一般的。そして最ももろい。タブ名は、 ユーザーが自由に変える唯一のものだからです。 - インデックスで —
Worksheets(1)— 左から右への位置です。「最初のシート」には便利ですが、誰かがタブを ドラッグして回った途端に役立たずになります。 - CodeName で —
Sheet1— プロパティウィンドウで、開発者だけが変えられる内部名です。ユーザーには 見えないので、彼らがタブに何をしても生き残ります。
どの識別子を使うかを選ぶことは、そのまま マクロがどれだけ脆くなるかを選ぶことです。それがこの記事の 教訓のすべてです。
3つの参照の道具の中の Worksheets コレクション
シートを名指しするのは参照の半分にすぎません — それがどのブックに住んでいるかも言わなければなりません。 そこで、このクラスターの他の2つの道具の出番です。
| 道具 | 何を指すか | 何と組み合わせるか |
|---|---|---|
| ThisWorkbook | このコードを抱えるブック — 不動 | .Worksheets("Jan") で自分のファイルの特定のタブに届く |
| ActiveWorkbook / ActiveSheet | 今いちばん手前にあるもの — 気まぐれ | 稀に — 汎用ツールのときだけ |
Worksheets(...) |
ブック内の名前付きシート | 常に前にブックを置く — ThisWorkbook.Worksheets(...) |
クラスターを結ぶルールは、ここにも当てはまります。限定なしの Worksheets("Jan") は、アクティブなブックの
中へ手を伸ばします。 前にブックを置いてください — ThisWorkbook.Worksheets("Jan") — そうすれば、シートは、
ユーザーが最後にクリックしたものではなく、あなたが意味するファイルの中で探されます。
Worksheets と Sheets:噛みついてくる違い
Worksheets と Sheets は交換可能に見え、たいていはそう振る舞いますが、同じコレクションではありません。
Sheets は すべての タブ — ワークシート と グラフシート — を含みます。Worksheets は、あなたが
入力するグリッドのシートだけを含みます。
Debug.Print ThisWorkbook.Worksheets.Count ' グリッドのシートだけ
Debug.Print ThisWorkbook.Sheets.Count ' グリッドのシート + グラフシート
ほとんどのブックにはグラフシートがないので、2つのカウントは一致し、誰も気づきません。グラフシートを1つ
加えると数が食い違います — そして、すべての要素がワークシートだと仮定して Sheets をループすると、
グラフシートに当たり、ワークシート専用のプロパティでエラーになります。グリッドのシートを意味するなら
Worksheets を使ってください — それはほとんど常にです。Sheets に手を伸ばすのは、ループにグラフシートも
意図的に入れたいときだけにします。
シートを名指しする3つの方法と、それぞれを壊すもの
ユーザーと開発者が実際にやる2つのこと — タブのリネームと並べ替え — に対して、3つを並べてみましょう。
' 名前で:読みやすいが、タブ名はユーザーが編集できる
Set ws = ThisWorkbook.Worksheets("Jan")
' ユーザーがタブを "January" にリネーム -> Subscript out of range
' インデックスで:位置ベース、タブが動くまでは問題ない
Set ws = ThisWorkbook.Worksheets(1)
' ユーザーが "Summary" を先頭にドラッグ -> 今や間違ったシートを指す
' CodeName で:開発者だけの内部名、ユーザーには見えない
Set ws = Sheet1
' タブをリネーム、タブを並べ替え -> 依然として同じシート
名前は最も読みやすく、ユーザーが最も壊しやすいものです。インデックスはリネームには耐えますが、並べ替えには
耐えません。CodeName — VBAエディターのプロパティウィンドウの (Name) で一度だけ設定する — は、両方に
耐える唯一のものです。Excelの画面には、それを変えるボタンがないからです。ツールの一部として同梱される
どのシートにとっても、CodeName が頑丈な参照です。
静かな罠:リネームで死ぬマクロ
これがサポートチケットを生む失敗です。あなたのマクロは Worksheets("Data") を読み、何か月も動きます。
あるユーザーが片付けをして、タブを Data から 2026 Data にリネームします。コードは何も変わっていない
のに、いまやどの実行も、シートを名指しする行で Subscript out of range で止まります — しかもメッセージは、
実際の原因であるリネームではなく、検索を指しています。
' もろい - リネーム1回で壊れる
ThisWorkbook.Worksheets("Data").Range("A1").Value = total
' 頑丈 - CodeName はExcelの画面から変えられない
Sheet1.Range("A1").Value = total
どうしてもタブ名をキーにする必要があるなら(ユーザーが作るシートなど)、守りを固めてください — 触れる前に シートの存在を確認するか、コレクションをループして一致させます。ですが、あなたが所有するシートについては、 脆さをまるごと飛ばして CodeName を使ってください。それが、片付けを生き延びるマクロと、そうでないマクロの 違いです。
意見:一度だけ、限定して Set し、CodeName を優先する
シートは一度だけ、マクロの先頭で、Worksheet 変数に — ブックで限定して — 指定し、以後はどこでもその変数を
通して作業してください。読みやすくなり、行ごとにシートを再検索するより速く、1つの脆い参照を、コード中に
散らばらせる代わりに、ちょうど1か所に置けます。
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Jan") ' 検索は一度、限定つき
ws.Range("A1").Value = 100
ws.Range("A2").Value = 200 ' 再検索なし、曖昧さなし
あなたが管理するシートには、その参照を CodeName にしてください(Set ws = Sheet1)。そうすれば、ユーザーに
よるタブのリネームがあなたのコードに届くことは決してありません。名前の文字列は、ユーザーが所有するシートの
ために取っておき、それらは守りを固めます。目標は、このクラスター全体を貫くものと同じです — どのオブジェクトを
意味するかを、一度、正確に言い、マクロに推測させないことです。
シートを追いかけるより、説明したいとき
シートとの戦いの半分は帳簿づけです — どのタブか、どの名前か、まだ存在するか、どのブックにあるか。 ExcelMaster なら、その帳簿づけを 飛ばせます。結果を説明するだけ — 「このファイルの毎月のタブすべてについて、D列を合計してサマリーシートに 入れて」 — で、各参照を限定し、欠けているシートやリネームされたシートを扱うコードを、まずブックをバック アップしたうえで書いて実行します。あなたは欲しい結果を名指しするだけ。ExcelMaster がシートを安全に解決 するので、リネームや並べ替えでマクロまるごとが倒れることはありません。
よくある質問
VBAのWorksheetsとSheetsの違いは?
Worksheets はグリッドのワークシートだけのコレクションです。Sheets は、グラフシートを含むすべての
タブのコレクションです。ブックにグラフシートがなければ同じものを返しますが、すべての要素がワークシート
だと仮定して Sheets をループすると、グラフシートでエラーになります。グラフシートを特に含めたいので
ない限り、Worksheets を使ってください。
VBAでワークシートを名前で参照するには?
前にブックを置いて ThisWorkbook.Worksheets("SheetName") を使い、検索があなたの意味するファイルの中で
起きるようにします。名前はタブの文字と正確に一致しなければならず、シートが存在しなければ
Subscript out of range になります。あなたが管理するシートには、ユーザーが変えられない CodeName のほうが
頑丈な参照です。
VBAのワークシートのCodeNameとは?
CodeName は、シートの内部名 — Sheet1 のような — で、VBAエディターのプロパティウィンドウの (Name) で
設定します。タブ名と違い、ユーザーがExcelの画面から変える方法はないので、Sheet1.Range("A1") のような
参照は、タブがリネームや移動されたあとでも動き続けます。
VBAでワークシートを変数に設定するには?
Dim ws As Worksheet で宣言し、次に Set ws = ThisWorkbook.Worksheets("Jan")(CodeName なら
Set ws = Sheet1)とします。ブックで限定して一度だけ設定すれば、マクロの残りは、シートを再検索したり、
何がアクティブかに依存したりせずに、ws を通して動きます。
WorksheetsでSubscript out of rangeが出るのはなぜですか?
あなたが求めた名前かインデックスがコレクションにないからです — 多くは、リネームや削除されたタブ、あるいは スペルミスや余分なスペースで入力された名前です。触れる前にシートの存在を確認するか、CodeName で参照して、 リネームが検索を壊せないようにしてください。
検証環境
検証環境: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-09-07.
関連ガイド: VBA ThisWorkbook · VBA ActiveWorkbook · VBA Worksheet · VBA Range · VBA Cells
