シートの存在チェック
「指定名のシートがあるか」を事前に確認できると、ランタイムエラーを防げます。初心者でも安全に使える関数テンプレートと、実務でそのまま役立つ例題をまとめました。
基本:関数で存在判定(最短・安全)
Function SheetExists(sheetName As String, Optional wb As Workbook) As Boolean
Dim t As Worksheet
If wb Is Nothing Then Set wb = ThisWorkbook
On Error Resume Next
Set t = wb.Worksheets(sheetName)
SheetExists = Not t Is Nothing
On Error GoTo 0
End Function
Sub Example_BasicCheck()
If SheetExists("売上") Then
MsgBox "『売上』シートは存在します。"
Else
MsgBox "『売上』シートは存在しません。"
End If
End Sub
VB- ポイント:
- エラー回避: ない名前を
Worksheets("名前")で参照するとエラーになるため、On Error Resume Nextで安全に判定。 - 対象ブック: ThisWorkbook(マクロ格納)とActiveWorkbook(操作中)の違いを意図で使い分け。
- エラー回避: ない名前を
ループ版:エラーを使わない判定(読みやすい)
Function SheetExistsLoop(sheetName As String, Optional wb As Workbook) As Boolean
Dim ws As Worksheet
If wb Is Nothing Then Set wb = ThisWorkbook
For Each ws In wb.Worksheets
If ws.Name = sheetName Then
SheetExistsLoop = True
Exit Function
End If
Next
End Function
VB- ポイント:
- 可読性重視: 例外制御が苦手ならループ版がわかりやすい。
- 拡張しやすい: 可視限定や部分一致などの条件を足しやすい。
応用テンプレート:大小無視/部分一致/可視限定
Function SheetExistsCaseInsensitive(sheetName As String, Optional wb As Workbook) As Boolean
Dim ws As Worksheet
If wb Is Nothing Then Set wb = ThisWorkbook
For Each ws In wb.Worksheets
If StrComp(ws.Name, sheetName, vbTextCompare) = 0 Then
SheetExistsCaseInsensitive = True
Exit Function
End If
Next
End Function
Function SheetExistsByPartial(partial As String, Optional wb As Workbook) As Boolean
Dim ws As Worksheet
If wb Is Nothing Then Set wb = ThisWorkbook
For Each ws In wb.Worksheets
If InStr(1, ws.Name, partial, vbTextCompare) > 0 Then
SheetExistsByPartial = True
Exit Function
End If
Next
End Function
Function VisibleSheetExists(sheetName As String, Optional wb As Workbook) As Boolean
Dim ws As Worksheet
If wb Is Nothing Then Set wb = ThisWorkbook
For Each ws In wb.Worksheets
If ws.Name = sheetName And ws.Visible = xlSheetVisible Then
VisibleSheetExists = True
Exit Function
End If
Next
End Function
VB- ポイント:
- 大小無視: 名前の大小が揺れる実ファイルに便利。
- 部分一致: 「売上」「Sales」などの揺れに対応。
- 可視限定: 非表示シートを除外したい画面操作前に有効。
Tryパターン:安全取得と併用(存在すれば返す)
Function TryGetSheetByName(sheetName As String, Optional wb As Workbook) As Worksheet
If wb Is Nothing Then Set wb = ThisWorkbook
On Error Resume Next
Set TryGetSheetByName = wb.Worksheets(sheetName)
On Error GoTo 0
End Function
Sub Example_TryGetThenUse()
Dim ws As Worksheet
Set ws = TryGetSheetByName("設定")
If ws Is Nothing Then
MsgBox "『設定』シートは存在しません。"
Else
ws.Range("A1").Value = "OK"
End If
End Sub
VB- ポイント:
- 取得と判定を一度に: 見つかればそのまま操作、なければ
Nothingで分岐。
- 取得と判定を一度に: 見つかればそのまま操作、なければ
実務テンプレート:なければ作る/他ブック対応
Function GetOrCreateSheet(sheetName As String, Optional wb As Workbook) As Worksheet
Dim ws As Worksheet
If wb Is Nothing Then Set wb = ThisWorkbook
Set ws = TryGetSheetByName(sheetName, wb)
If ws Is Nothing Then
Set ws = wb.Worksheets.Add(After:=wb.Worksheets(wb.Worksheets.Count))
ws.Name = SanitizeSheetName(sheetName, wb)
End If
Set GetOrCreateSheet = ws
End Function
Function SanitizeSheetName(rawName As String, wb As Workbook) As String
Dim s As String: s = Trim$(rawName)
s = Replace(s, ":", "_"): s = Replace(s, "/", "_")
s = Replace(s, "\", "_"): s = Replace(s, "?", "_")
s = Replace(s, "*", "_"): s = Replace(s, "[", "_")
s = Replace(s, "]", "_")
If Len(s) = 0 Then s = "Sheet"
If Len(s) > 31 Then s = Left$(s, 31)
'重複回避
Dim base As String: base = s
Dim i As Long: i = 1
Do While SheetExists(s, wb)
i = i + 1
s = IIf(Len(base) > 28, Left$(base, 28), base) & "_" & CStr(i)
Loop
SanitizeSheetName = s
End Function
Sub Example_OtherWorkbook()
Dim wb As Workbook, ws As Worksheet
Set wb = Workbooks("月次集計.xlsm") '既に開いているブック
Set ws = GetOrCreateSheet("売上", wb)
ws.Range("A1").Value = "準備完了"
End Sub
VB- ポイント:
- 存在しなければ作成: 事故のない自動生成。
- 禁止文字・重複対策: 命名は必ず安全化してから行う。
- 他ブック:
Optional wbで柔軟に対象を切替。
例題で練習
例題1:存在すれば書き込み、なければ警告
Sub WriteIfExists()
If SheetExists("ログ") Then
ThisWorkbook.Worksheets("ログ").Cells(1, 1).Value = Now
Else
MsgBox "『ログ』シートがありません。"
End If
End Sub
VB- ポイント:
- 定番分岐: エラー無く「有れば使う/無ければ伝える」。
例題2:一覧(Control!A2:A)に書かれた名前だけ作成(存在チェック込み)
Sub EnsureSheetsFromList()
Dim ctrl As Worksheet, last As Long, r As Long, nm As String
Set ctrl = ThisWorkbook.Worksheets("Control")
last = ctrl.Cells(ctrl.Rows.Count, "A").End(xlUp).Row
For r = 2 To last
nm = CStr(ctrl.Cells(r, "A").Value)
Call GetOrCreateSheet(nm, ThisWorkbook)
Next
MsgBox "一覧に基づき、必要なシートを準備しました。"
End Sub
VB- ポイント:
- 運用自動化: 名称リストを「マスタ」にして不足分を自動生成。
例題3:部分一致で存在確認し、最初に見つかったシートへ移動
Sub ActivateFirstPartial(partial As String)
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
If InStr(1, ws.Name, partial, vbTextCompare) > 0 Then
ws.Activate
MsgBox "移動先: " & ws.Name
Exit Sub
End If
Next
MsgBox "「" & partial & "」を含むシートはありません。"
End Sub
Sub Example_PartialMove()
ActivateFirstPartial "売上"
End Sub
VB- ポイント:
- 揺れに強い: 部分一致で柔軟にヒットさせる。
実務の落とし穴と対策
- エラー9(インデックスが有効範囲にありません):
- 原因: 存在しない名前を
Worksheets("名前")で参照。 - 対策: かならず存在チェック関数を通してから参照・操作。
- 原因: 存在しない名前を
- ThisWorkbookとActiveWorkbookの混同:
- 対策: どちらを対象にするか処理ごとに明確化し、引数
wbで統一。
- 対策: どちらを対象にするか処理ごとに明確化し、引数
- 日本語名・禁止文字・31文字上限:
- 対策: 入力文字列から作るときは必ず
SanitizeSheetNameを挟む。
- 対策: 入力文字列から作るときは必ず
- 非表示シートの扱い:
- 対策: 画面操作(Select/Activate)前は、可視チェックを入れるか、画面操作を避けてオブジェクト参照で処理。
次の一歩(小課題)
- 課題1:
InputBoxで受け取った名前について「存在すればA1へ時刻書き込み/なければ安全に作成」するマクロ。 - 課題2: 「tmp」「draft」を含むシートの存在チェックを行い、見つかった件数をメッセージで報告。
- 課題3: 他ブック(例:Workbooks(“報告.xlsm”))に対して、一覧にない余分なシートを列挙してログ出力。
