【VBA】Select Caseで複数条件の分岐をスッキリ書く方法(コピペOK)

VBA
スポンサーリンク
スポンサーリンク
  1. この記事でわかること
    1. どんな場面で使う?
  2. 完成イメージ(Before / After)
  3. 実行前の準備
    1. バックアップを取る
    2. Excelをマクロ有効ブック(.xlsm)で保存する
  4. 手順(コピペ → 実行まで約5分)
    1. VBE(コードを書く画面)を開く
    2. 標準モジュールを挿入する
    3. コードを貼り付けて実行する
  5. コード(基本版)– 点数→評価のランク分け(Select Case Is)
    1. 書き換えポイント
  6. コード(応用版)– 文字列パターンマッチ+範囲指定
    1. パターン1: 範囲指定(Case 値1 To 値2)
    2. パターン2: カンマ区切りで複数値(Case 値1, 値2, 値3)
    3. パターン3: 複合条件(Select Case True)
  7. コード(実務版)– セルの値に応じて処理を振り分け(部門コード→処理分岐)
    1. 書き換えポイント
    2. シート構成の例
  8. よくある落とし穴5選
    1. 1. Case節の範囲が重複して、後のCaseが実行されない
    2. 2. セルの値が文字列型の数字で、数値比較が意図通りにならない
    3. 3. Case Elseを書かず、想定外のデータがスルーされる
    4. 4. 文字列の大文字・小文字が区別されてしまう
    5. 5. Select Case Trueで条件式を間違えて全Caseがスルーされる
    6. VBAのSelect Caseが動かない・分岐しないときの対処法
    7. VBAのCase条件が一致しないときの対処法
  9. FAQ
    1. Q1: Select CaseとIf…ElseIfはどう使い分ける?
    2. Q2: Case節にカンマで複数の値を書ける?
    3. Q3: Case IsとCase Toは同じCase節で併用できる?
    4. Q4: Select Case Trueとは何?
    5. Q5: Select Caseの中でExit SubやGoToは使える?
  10. まとめ
    1. 関連記事
  11. 次にやりたくなること

この記事でわかること

  • Select Caseの基本構文で、If…ElseIfの連続をスッキリ書き直せる
  • Case Is(比較演算)・Case To(範囲指定)・Case True(複合条件)の3パターンを使い分けられる
  • セルの値に応じて処理を振り分ける実務コードがコピペで動く

対象: Excel 2016以降 / Microsoft 365、Windows 10/11

どんな場面で使う?

  • 点数やスコアのランク分け — テストの点数、顧客満足度、品質検査の結果などを自動でS/A/B/C/Dに振り分けたい
  • 部門コード・商品コードによる処理分岐 — コードの値に応じて処理区分や担当部署を自動で判定したい
  • 月や曜日による四半期・平日/休日の判定 — 日付データから四半期を出したり、平日か休日かを自動で分類したい
  • ステータスコードに応じたメッセージ表示 — 「完了」「処理中」「エラー」などの状態に応じて異なるアクションを実行したい
  • If…ElseIfが5段以上になったコードの整理 — 既存のIf文の連続を、読みやすく・追加しやすいSelect Caseに書き直したい

完成イメージ(Before / After)

Before(If…ElseIfの連続):


If score >= 90 Then
    rank = "S"
ElseIf score >= 80 Then
    rank = "A"
ElseIf score >= 70 Then
    rank = "B"
ElseIf score >= 60 Then
    rank = "C"
Else
    rank = "D"
End If

After(Select Caseで書き直し):


Select Case score
    Case Is >= 90: rank = "S"
    Case Is >= 80: rank = "A"
    Case Is >= 70: rank = "B"
    Case Is >= 60: rank = "C"
    Case Else:     rank = "D"
End Select

判定対象(score)を1回書くだけ。条件を追加するときもCase行を1行足すだけで済む。

自分も以前、If…ElseIfを10個以上並べて条件分岐を書いていた。条件を追加するたびに「ElseIfをどこに挟むか」を探すのが地味にストレスだった。Select Caseに書き換えてからは、条件の追加も削除もCase行を1行足す・消すだけで済むようになった。コードの見通しが格段に良くなって、もっと早く知りたかったと思った。If文の連続で読みにくいコードに悩んでいる人が、この記事でSelect Caseをサクッと使えるようになればうれしい。

Select Caseを使えば、1つの値に対する複数条件の分岐がスッキリ書ける。

なお、Select Case内でエラーが起きた場合の対処は エラー処理(On Error)で止まらないマクロを作る方法 を参照。

実行前の準備

バックアップを取る

実務版コードはセルの値を書き換える(C列を上書き)。必ずファイルのコピーを別フォルダに保存してから実行する。

Excelをマクロ有効ブック(.xlsm)で保存する

拡張子が .xlsx のままだとマクロが保存できない。

  1. 「ファイル」→「名前を付けて保存」
  2. ファイルの種類を「Excelマクロ有効ブック (*.xlsm)」に変更
  3. 保存

手順(コピペ → 実行まで約5分)

VBE(コードを書く画面)を開く

  1. Excelで Alt + F11 を押す

標準モジュールを挿入する

  1. VBEのメニュー →「挿入」→「標準モジュール」

コードを貼り付けて実行する

  1. コードウィンドウに、下のコードをそのままコピペする
  2. Alt + F8 → マクロ名を選んで「実行」

ボタンに割り当てれば毎回Alt+F8を押さなくて済む。方法は マクロをボタン1つで実行する方法 を参照。

コード(基本版)– 点数→評価のランク分け(Select Case Is)

セルA1の点数を読み取り、評価ランクをMsgBoxで表示する。まずはこれで動きを確認する。


'============================================================
' ■ 点数→評価ランクの判定(基本版)
'   → セルA1の値を読み取り、S/A/B/C/D にランク分け
'============================================================
Sub JudgeRank()

    Dim score As Long
    score = CLng(Range("A1").Value)  '← セルA1の値を数値に変換

    Dim rank As String

    Select Case score
        Case Is >= 90
            rank = "S"
        Case Is >= 80
            rank = "A"
        Case Is >= 70
            rank = "B"
        Case Is >= 60
            rank = "C"
        Case Else
            rank = "D"
    End Select

    MsgBox "点数: " & score & vbCrLf & "評価: " & rank, vbInformation

End Sub

書き換えポイント

変数 説明 初期値
Range("A1") 点数が入っているセル A1
各Caseの閾値 ランクの境界値 90 / 80 / 70 / 60
rank の値 各ランクの表示文字 "S" / "A" / "B" / "C" / "D"

ポイント: Select Caseは上から順に評価し、最初にマッチしたCaseだけ実行する。Case Is >= 90 を先に書くことで、90以上はここで確定し、次の Case Is >= 80 には流れない。これはC言語のswitch文とは違い、break を書かなくても次のCaseに「落ちない」ということだ。この仕組みのおかげで、条件の順序さえ正しければバグが起きにくい。

なぜIf…ElseIfではなくSelect Caseで書くのかというと、判定対象が1つの変数(この例では score)に集中しているからだ。If文だと毎行 score >= 〇〇 と書く必要があるが、Select Caseなら score は先頭で1回書くだけで済む。条件を追加・削除するときもCase行を1行足す・消すだけなので、メンテナンス性が圧倒的に高い。

MsgBoxの使い方の詳細は MsgBoxでユーザーに確認ダイアログを出す方法 を参照。

コード(応用版)– 文字列パターンマッチ+範囲指定

パターン1: 範囲指定(Case 値1 To 値2)

月を入力して四半期を判定する例。


'============================================================
' ■ 月→四半期の判定(応用版: Case To)
'   → セルA1の月(1〜12)を読み取り、四半期を表示
'============================================================
Sub JudgeQuarter()

    Dim mon As Long
    mon = CLng(Range("A1").Value)

    Dim quarter As String

    Select Case mon
        Case 4 To 6
            quarter = "Q1(4〜6月)"
        Case 7 To 9
            quarter = "Q2(7〜9月)"
        Case 10 To 12
            quarter = "Q3(10〜12月)"
        Case 1 To 3
            quarter = "Q4(1〜3月)"
        Case Else
            quarter = "該当なし(1〜12の値を入力してください)"
    End Select

    MsgBox mon & "月 → " & quarter, vbInformation

End Sub

パターン2: カンマ区切りで複数値(Case 値1, 値2, 値3)

曜日コード(1〜7)で平日・土日を判定する例。


'============================================================
' ■ 曜日コード→平日/土日の判定(応用版: カンマ区切り)
'   → Weekday関数の戻り値(1=日, 2=月, ..., 7=土)で判定
'============================================================
Sub JudgeDayType()

    Dim wDay As Long
    wDay = Weekday(Date)  '← 今日の曜日コード

    Dim dayType As String

    Select Case wDay
        Case 2, 3, 4, 5, 6  '← 月〜金
            dayType = "平日"
        Case 1, 7            '← 日・土
            dayType = "休日"
        Case Else
            dayType = "判定不能"
    End Select

    MsgBox "今日(" & Format(Date, "yyyy/mm/dd") & ")は " & dayType & " です。", vbInformation

End Sub

日付の書式設定は Format関数で表示形式を整える方法 も参考になる。

パターン3: 複合条件(Select Case True)

1つの変数だけでなく、複数の条件を組み合わせたい場合に使う。セルA1に点数、B1に出席率(0.85 = 85%)が入っている前提。セルが空の場合は基本版で動作確認してから試すとよい。


'============================================================
' ■ 複合条件の判定(応用版: Select Case True)
'   → 点数と出席率の両方で総合評価を判定
'============================================================
Sub JudgeComplex()

    Dim score As Long
    score = CLng(Range("A1").Value)  '← 点数

    Dim attendance As Double
    attendance = CDbl(Range("B1").Value)  '← 出席率(例: 0.85 = 85%)

    Dim result As String

    Select Case True
        Case score >= 90 And attendance >= 0.9
            result = "優秀"
        Case score >= 70 And attendance >= 0.7
            result = "合格"
        Case score >= 50
            result = "条件付き合格"
        Case Else
            result = "不合格"
    End Select

    MsgBox "点数: " & score & vbCrLf & _
           "出席率: " & Format(attendance, "0%") & vbCrLf & _
           "判定: " & result, vbInformation

End Sub

ポイント: Select Case True は「Trueに一致するCaseを探す」仕組み。各Case節に条件式を書けるので、複数の変数を組み合わせた分岐が可能。ただし、単純な1変数の分岐なら通常のSelect Caseの方が読みやすい。

なぜ Select Case True という書き方が必要かというと、通常のSelect Caseは「1つの値」に対する分岐しかできないからだ。scoreattendance のように2つの変数を同時に判定したい場合、通常のSelect Caseでは書けない。Select Case True なら各Case節にAnd条件やOr条件を自由に書けるので、If…ElseIfの代替としても使える。ただし、条件式がすべてFalseの場合はCase Elseに入る(Case Elseがなければ何も実行されない)ので、必ずCase Elseを書いておくのが安全だ。

型変換(CLng, CDbl)の詳細は 型変換関数で「型が一致しません」エラーを防ぐ方法 を参照。

コード(実務版)– セルの値に応じて処理を振り分け(部門コード→処理分岐)

A列に部門コード、B列に売上が入った一覧表を処理する例。部門コードに応じてC列に「処理区分」を書き込む。

部門コードで処理を振り分けるマクロをSelect Caseで書くようにしてからは、部門が増えてもCase行を1行追加するだけで対応できている。修正依頼にもすぐ対応できるようになった。

コード解説:

この実務版コードは、A列の部門コードを1行ずつ読み取り、Select Caseで処理区分を判定し、C列に結果を書き込む構成だ。Case "A01", "A02", "A03" のようにカンマ区切りで複数コードをまとめられるのがSelect Caseの強みで、If文で書くと If code = "A01" Or code = "A02" Or code = "A03" Then と冗長になる。Case "C01" To "C99" は文字列の範囲指定で、C01からC99までの辞書順の範囲にマッチする。売上額による追加判定(If sales >= 1000000)はSelect Caseの後にIf文で処理しているが、これは「コード判定」と「金額判定」が別軸の条件だからだ。1軸はSelect Case、別軸はIf文という使い分けが実務では多い。

※ C列の既存データは上書きされます。実行前にバックアップを取ってください。


'============================================================
' ■ 部門コード→処理区分の振り分け(実務版)
'   → A列: 部門コード、B列: 売上、C列: 処理区分を書き込み
'   → 対象シート: アクティブシート
'============================================================
Sub ClassifyByDepartment()

    '--- ★書き換えポイント ---
    Dim startRow As Long
    startRow = 2                '← データの開始行(1行目はヘッダー)

    Dim codeCol As Long
    codeCol = 1                 '← 部門コードの列(A列=1)

    Dim salesCol As Long
    salesCol = 2                '← 売上の列(B列=2)

    Dim resultCol As Long
    resultCol = 3               '← 処理区分を書き込む列(C列=3)
    '--- ★ここまで ---

    Dim ws As Worksheet
    Set ws = ActiveSheet

    '--- 最終行を取得
    Dim lastRow As Long
    lastRow = ws.Cells(ws.Rows.Count, codeCol).End(xlUp).Row

    If lastRow < startRow Then
        MsgBox "データがありません。", vbExclamation
        Exit Sub
    End If

    '--- ループで使う変数を事前宣言
    Dim r As Long
    Dim processCount As Long
    Dim code As String
    Dim sales As Double
    Dim category As String
    processCount = 0

    For r = startRow To lastRow

        code = Trim(CStr(ws.Cells(r, codeCol).Value))

        '--- 売上を数値に変換(変換できない場合は0にする)
        On Error Resume Next
        sales = CDbl(ws.Cells(r, salesCol).Value)
        If Err.Number <> 0 Then
            sales = 0
            Err.Clear
        End If
        On Error GoTo 0

        Select Case code
            Case "A01", "A02", "A03"
                category = "本社管轄"
            Case "B01", "B02"
                category = "支社管轄"
            Case "C01" To "C99"
                category = "工場管轄"
            Case "X00"
                category = "対象外"
            Case ""
                category = "(コード未入力)"
            Case Else
                category = "不明コード: " & code
        End Select

        '--- 売上が一定額以上なら追加情報を付加
        If sales >= 1000000 Then
            category = category & "【要確認】"
        End If

        ws.Cells(r, resultCol).Value = category
        processCount = processCount + 1

    Next r

    MsgBox processCount & " 行の処理区分を書き込みました。", vbInformation

End Sub

書き換えポイント

変数 説明 初期値
startRow データの開始行 2(1行目はヘッダー)
codeCol 部門コードの列 1(A列)
salesCol 売上の列 2(B列)
resultCol 処理区分の書き込み列 3(C列)
Case節の値 部門コードと処理区分の対応 自社の部門コードに合わせて変更

シート構成の例

A列(部門コード) B列(売上) C列(処理区分)← マクロで書き込み
A01 500000 本社管轄
B01 1200000 支社管轄【要確認】
C15 300000 工場管轄
X00 0 対象外
Z99 100000 不明コード: Z99

よくある落とし穴5選

1. Case節の範囲が重複して、後のCaseが実行されない

自分もこれでハマった。Case 1 To 100 を先に書いて、その下の Case 1 To 50 が永遠に通らなかった。原因に気づくまで30分は溶かした。

原因: Select Caseは上から順に評価し、最初にマッチしたCaseだけ実行する。範囲が広いCaseを先に書くと、狭い範囲のCaseが評価されない。

対策: 範囲が狭い(条件が厳しい)Caseを先に書く。


' NG: 80〜100がCase 1 To 100に吸い込まれる
Select Case score
    Case 1 To 100: rank = "普通"
    Case 80 To 100: rank = "優秀"  '← ここに来ない
End Select

' OK: 範囲が狭いCaseを先に
Select Case score
    Case 80 To 100: rank = "優秀"
    Case 1 To 79:   rank = "普通"
End Select

2. セルの値が文字列型の数字で、数値比較が意図通りにならない

原因: セルに '100 のように先頭にアポストロフィが付いた値や、CSV取り込み時に文字列として格納された数字は、文字列型になっている。文字列同士の比較は辞書順になるため、"9" > "80" が True になる。

対策: CLng()CDbl() で数値に変換してからSelect Caseに渡す。

3. Case Elseを書かず、想定外のデータがスルーされる

原因: Case Elseを省略すると、どのCaseにも該当しないデータは何も処理されずに通過する。バグの原因になりやすい。

対策: 必ずCase Elseを書く。想定外のデータが来たことを検知できるようにする。

4. 文字列の大文字・小文字が区別されてしまう

原因: VBAの文字列比較は既定で大文字小文字を区別する(バイナリ比較)。Case "abc""ABC" にマッチしない。

対策: モジュールの先頭(Option Explicit の下)に Option Compare Text を追加するか、UCase()LCase() で統一してからSelect Caseに渡す。


Option Explicit
Option Compare Text  '← Option Explicitの下に追加

' これで Case "abc" が "ABC" にもマッチするようになる

5. Select Case Trueで条件式を間違えて全Caseがスルーされる

原因: 各Case節の条件式がすべてFalseの場合、Case Elseに入る(Case Elseがなければ何も実行されない)。条件式のロジックミスに気づきにくい。

対策: Case Elseで「想定外」を検知する。Debug.Print で判定対象の値を出力して確認する。

VBAのSelect Caseが動かない・分岐しないときの対処法

「Select Caseを書いたのに、どのCaseにも入らず何も実行されない」という場合、原因はSelect Caseに渡している値の型と、Case節で比較している値の型が一致していないことが多い。たとえばセルの値が文字列型の "100" なのに Case Is >= 90 で数値比較しようとすると、文字列と数値の比較になり意図通りにマッチしない。対策として、Select Caseに渡す前に CLng()CDbl() で数値に変換するか、CStr() で文字列に統一する。Case Elseに Debug.Print を入れておくと、想定外の値が来たときにイミディエイトウィンドウで原因を追えるようになる。

VBAのCase条件が一致しないときの対処法

「Case “abc” と書いているのに、セルの値が “ABC” のときマッチしない」という場合、原因はVBAの文字列比較がデフォルトで大文字・小文字を区別する(バイナリ比較)ことだ。対策として、モジュールの先頭(Option Explicit の下)に Option Compare Text を追加すれば、大文字・小文字を区別しない比較になる。もう1つの方法として、Select Caseに渡す前に UCase()LCase() で統一する手もある。自分はチーム共有のマクロでは Option Compare Text を標準にしていて、入力のブレによるバグを防いでいる。

FAQ

Q1: Select CaseとIf…ElseIfはどう使い分ける?

使い分け Select Case If…ElseIf
1つの値に対する複数分岐 向いている 冗長になりがち
複数の変数を組み合わせた条件 Select Case Trueで可能だが可読性が下がる 向いている
2〜3個の分岐 どちらでもOK If文の方がシンプル
5個以上の分岐 Select Caseの方が見やすい ElseIfの連続が長くなる

結論: 1つの値に対して分岐が5個以上ならSelect Case。2〜3個ならIf文で十分。複数変数の複雑な条件はIf文が向いている。

Q2: Case節にカンマで複数の値を書ける?

書ける。Case 1, 3, 5, 7 のようにカンマ区切りで指定可能。文字列でも Case "A01", "A02", "A03" のように書ける。

Q3: Case IsとCase Toは同じCase節で併用できる?

できる。カンマで区切って併用可能。


Select Case score
    Case 1 To 5, Is >= 95  '← 1〜5 または 95以上が対象
        MsgBox "特別対応"
    Case Else
        MsgBox "通常対応"   '← 6〜94はここに入る
End Select

Q4: Select Case Trueとは何?

Select Case True は各CaseにBoolean式(条件式)を書く方法。Trueに一致するCaseが実行される。


Select Case True
    Case score >= 90 And attendance >= 0.9
        result = "優秀"
    Case score >= 70
        result = "合格"
End Select

複数の変数を組み合わせた分岐に使えるが、単純な分岐には通常のSelect Caseの方が読みやすい。

Q5: Select Caseの中でExit SubやGoToは使える?

使える。Case節の中でExit SubやGoToを書けばその場で処理を抜けられる。ただし、GoToの多用はコードの可読性を下げるので推奨しない。

まとめ

  • Select Case: 1つの値に対する複数条件の分岐をスッキリ書ける
  • Case Is: 比較演算子を使う分岐(Case Is >= 90
  • Case To: 範囲指定の分岐(Case 1 To 10
  • Case カンマ区切り: 複数値の一括指定(Case 1, 3, 5
  • Case Else: 必ず書く。想定外のデータを検知する
  • Select Case True: 複合条件の分岐に使えるが、単純なら通常のSelect Caseで

Select Caseは「1つの値に対する複数の条件分岐」をスッキリ書くための構文だ。自分の実感として、If…ElseIfが5行を超えたらSelect Caseへの書き換えを検討する価値がある。コードの見通しが良くなるだけでなく、条件の追加・削除・並び替えが1行単位でできるようになるため、運用フェーズでのメンテナンスが格段にラクになる。まずは基本版の点数ランク分けで動きを確認し、慣れたら実務版の部門コード振り分けに進むのがおすすめだ。

関連記事

次にやりたくなること

コメント

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