Excel VBA 逆引き集 | シートの存在チェック

Excel VBA
スポンサーリンク

シートの存在チェック

「指定名のシートがあるか」を事前に確認できると、ランタイムエラーを防げます。初心者でも安全に使える関数テンプレートと、実務でそのまま役立つ例題をまとめました。


基本:関数で存在判定(最短・安全)

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”))に対して、一覧にない余分なシートを列挙してログ出力。

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