Excel VBA | ネストした Select Case

VBA
スポンサーリンク

ネストした Select Case の考え方と使い方

最初にひとつだけ伝えたいことがあります。ネスト(入れ子)は「条件が二段階以上あるとき」に使います。例えば「会員種別ごとに金額帯で割引が変わる」など。素直に書けば分かりやすく、複雑になるなら「前処理でひとつのキーにまとめる」ほうが読みやすくなります。


まずは基本形のネスト

例題: 会員種別 × 購入金額で割引率を決める

  • 目的: 会員種別(VIP/REG)でまず分け、次に金額帯で分ける。
Function CalcDiscount(memberType As String, amount As Currency) As Double
    memberType = UCase(memberType)

    Select Case memberType
        Case "VIP"
            Select Case amount
                Case Is >= 10000
                    CalcDiscount = 0.20
                Case 5000 To 9999
                    CalcDiscount = 0.15
                Case Else
                    CalcDiscount = 0.10
            End Select

        Case "REG"
            Select Case amount
                Case Is >= 10000
                    CalcDiscount = 0.10
                Case 5000 To 9999
                    CalcDiscount = 0.07
                Case Else
                    CalcDiscount = 0.03
            End Select

        Case Else
            CalcDiscount = 0
    End Select
End Function
Java
  • ポイント:
    • 外側: 会員種別で大枠のルールを分ける。
    • 内側: 同じ評価軸(金額)で段階を分ける。
    • Else: 想定外の入力に必ず備える。

ネストを選ぶ基準

  • 二段階の評価が明確: 例えば「種別→金額」「部署→職位」などはネストが素直。
  • 条件が独立している: 外側で一つ目の軸を確定し、内側で二つ目の軸を評価できる。
  • 読みやすさが維持できる範囲: ケースが爆発するなら、ネストを避ける工夫を検討。

文字判定 × 追加条件のネスト

例題: 商品カテゴリ × 在庫数で補充判定

  • 目的: カテゴリで基準が違い、在庫数に応じて補充可否を決める。
Sub RefillDecision(category As String, stock As Integer)
    category = UCase(category)

    Select Case category
        Case "FOOD"
            Select Case stock
                Case Is < 20: MsgBox "補充する(FOODの基準:20)"
                Case Else:    MsgBox "補充不要"
            End Select

        Case "BOOK"
            Select Case stock
                Case Is < 10: MsgBox "補充する(BOOKの基準:10)"
                Case Else:    MsgBox "補充不要"
            End Select

        Case "MEDICAL"
            Select Case stock
                Case Is < 5:  MsgBox "補充する(MEDICALの基準:5)"
                Case Else:    MsgBox "補充不要"
            End Select

        Case Else
            MsgBox "不明なカテゴリです"
    End Select
End Sub
Java
  • ポイント:
    • 閾値がカテゴリごとに違うときは、外側でカテゴリを固定してから内側で数値を判断すると読みやすい。
    • 同じ内側ロジック(stockの比較)を使い回せる。

ネストが深くなりそうなときの回避テクニック

1. ひとつのキーにまとめる(フラット化)

  • 考え方: 前処理で「軸を結合」して1段の Select Case にする。
Function CalcDiscountFlat(memberType As String, amount As Currency) As Double
    Dim key As String
    memberType = UCase(memberType)

    If amount >= 10000 Then
        key = memberType & "_HIGH"
    ElseIf amount >= 5000 Then
        key = memberType & "_MID"
    Else
        key = memberType & "_LOW"
    End If

    Select Case key
        Case "VIP_HIGH": CalcDiscountFlat = 0.20
        Case "VIP_MID":  CalcDiscountFlat = 0.15
        Case "VIP_LOW":  CalcDiscountFlat = 0.10
        Case "REG_HIGH": CalcDiscountFlat = 0.10
        Case "REG_MID":  CalcDiscountFlat = 0.07
        Case "REG_LOW":  CalcDiscountFlat = 0.03
        Case Else:       CalcDiscountFlat = 0
    End Select
End Function
Java
  • メリット: 1段に集約されて見通しが良い。パターン追加も楽。

2. ガード節(早期 return)で枝を減らす

  • 考え方: 想定外を先に返す、または一部ケースを先に処理してネストを浅くする。
Function ShippingFee(region As String, weight As Double) As Currency
    region = UCase(region)
    If weight <= 0 Then ShippingFee = 0: Exit Function

    Select Case region
        Case "LOCAL"
            If weight <= 1 Then ShippingFee = 300 Else ShippingFee = 500
        Case "REMOTE"
            If weight <= 1 Then ShippingFee = 600 Else ShippingFee = 900
        Case Else
            ShippingFee = 0
    End Select
End Function
Java
  • メリット: ネストの層を増やさず、意図をシンプルに。

つまずきやすいポイントとコツ

  • 重なる範囲の順序: 具体的で狭い条件を先に、広い条件を後に。
  • Case Else の徹底: 想定外の受け皿は必ず。テスト中の可視化にも役立つ。
  • 比較軸の揃え: 外側と内側で「何を比較しているか」がぶれないようにする。
  • 同じ処理の重複を避ける: 同じメッセージや計算は関数化して呼び出す。
  • 文字比較の標準化: UCase/LCase で大小統一。Trimで前後空白除去も有効。

実務向けの総合例

例題: 顧客セグメント × 受注金額 × 支払い方法で手数料を決定

  • 目的: ネストが増えそうなので「フラット化」と「ネスト」を併用。
Function CalcFee(segment As String, amount As Currency, pay As String) As Currency
    segment = UCase(segment)
    pay = UCase(pay)

    ' 早期終了(ガード)
    If amount <= 0 Then CalcFee = 0: Exit Function

    ' 金額帯キー化(フラット化)
    Dim band As String
    If amount >= 100000 Then
        band = "HIGH"
    ElseIf amount >= 20000 Then
        band = "MID"
    Else
        band = "LOW"
    End If

    ' 外側:セグメントでルールブロックを分割
    Select Case segment
        Case "VIP"
            Select Case band
                Case "HIGH": CalcFee = IIf(pay = "CARD", 0, 200)
                Case "MID":  CalcFee = IIf(pay = "CARD", 100, 300)
                Case "LOW":  CalcFee = IIf(pay = "CARD", 200, 400)
            End Select

        Case "REG"
            Select Case band
                Case "HIGH": CalcFee = IIf(pay = "CARD", 300, 500)
                Case "MID":  CalcFee = IIf(pay = "CARD", 400, 600)
                Case "LOW":  CalcFee = IIf(pay = "CARD", 500, 700)
            End Select

        Case Else
            CalcFee = 1000 ' 不明セグメントの標準手数料
    End Select
End Function
Java
  • ポイント:
    • 金額帯は前処理でバンド化してロジックを簡潔に。
    • 支払い方法は IIf で1行にまとめ、ネストを増やさない。
    • ガード節で不正データに早期対応。

練習課題

  • 課題1: 端末タイプ(PC/MOBILE/TABLET)ごとに、アクセス元(国内/海外)で表示言語を切り替えるネスト関数を書いてください。
  • 課題2: 返品可否を「商品カテゴリ × 購入からの日数」で判定。カテゴリごとに可否の閾値(日数)が違う前提で組んでください。
  • 課題3: 勤怠の「雇用形態 × 勤務時間帯(早朝/通常/深夜)」で割増率を返す関数を作成。重複する割増率は関数化して再利用してください。

解答例と解説

課題1: 端末タイプ(PC/MOBILE/TABLET) × アクセス元(国内/海外)で表示言語を切り替える

解答例

Function GetLanguage(device As String, region As String) As String
    device = UCase(device)
    region = UCase(region)

    Select Case device
        Case "PC"
            Select Case region
                Case "DOMESTIC": GetLanguage = "日本語"
                Case "OVERSEAS": GetLanguage = "英語"
                Case Else:       GetLanguage = "不明"
            End Select

        Case "MOBILE"
            Select Case region
                Case "DOMESTIC": GetLanguage = "日本語(モバイル用)"
                Case "OVERSEAS": GetLanguage = "英語(モバイル用)"
                Case Else:       GetLanguage = "不明"
            End Select

        Case "TABLET"
            Select Case region
                Case "DOMESTIC": GetLanguage = "日本語(タブレット用)"
                Case "OVERSEAS": GetLanguage = "英語(タブレット用)"
                Case Else:       GetLanguage = "不明"
            End Select

        Case Else
            GetLanguage = "不明な端末"
    End Select
End Function
Java

解説

  • 外側の Select Case で「端末タイプ」を判定。
  • 内側の Select Case で「地域」を判定。
  • ネストにより「二段階の条件分け」を自然に表現できる。

課題2: 商品カテゴリ × 購入からの日数で返品可否を判定

解答例

Function CanReturn(category As String, days As Integer) As String
    category = UCase(category)

    Select Case category
        Case "FOOD"
            Select Case days
                Case Is <= 3:  CanReturn = "返品可"
                Case Else:     CanReturn = "返品不可"
            End Select

        Case "BOOK"
            Select Case days
                Case Is <= 14: CanReturn = "返品可"
                Case Else:     CanReturn = "返品不可"
            End Select

        Case "ELECTRONICS"
            Select Case days
                Case Is <= 30: CanReturn = "返品可"
                Case Else:     CanReturn = "返品不可"
            End Select

        Case Else
            CanReturn = "カテゴリ不明"
    End Select
End Function
Java

解説

  • カテゴリごとに「返品可能な日数」が違う。
  • 外側でカテゴリを判定 → 内側で日数を判定。
  • ネストを使うことで「カテゴリごとのルール」を整理できる。

課題3: 勤怠の「雇用形態 × 勤務時間帯」で割増率を返す

解答例

Function GetExtraRate(jobType As String, shift As String) As Double
    jobType = UCase(jobType)
    shift = UCase(shift)

    Select Case jobType
        Case "FULLTIME"
            Select Case shift
                Case "EARLY":  GetExtraRate = 0.10
                Case "NORMAL": GetExtraRate = 0
                Case "NIGHT":  GetExtraRate = 0.25
                Case Else:     GetExtraRate = 0
            End Select

        Case "PARTTIME"
            Select Case shift
                Case "EARLY":  GetExtraRate = 0.05
                Case "NORMAL": GetExtraRate = 0
                Case "NIGHT":  GetExtraRate = 0.15
                Case Else:     GetExtraRate = 0
            End Select

        Case Else
            GetExtraRate = 0
    End Select
End Function
Java

解説

  • 外側で「雇用形態」を判定。
  • 内側で「勤務時間帯」を判定。
  • 割増率の違いを二段階で整理できる。

総まとめ

  • ネストした Select Case は「二段階の条件分け」に最適。
  • 外側で大枠を決め、内側で細かい条件を判定する。
  • Case Else を必ず用意して、想定外の入力を受け止める。
  • 複雑になりすぎる場合は「前処理でキーをまとめる」などの工夫も有効。
タイトルとURLをコピーしました