Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
学ぶ ループ | VBA基礎
ビジネス自動化のためのExcel VBA

ループ

メニューを表示するにはスワイプしてください

これまで紹介したテクニックは、すべて1つの値に対してのみ動作していました。ループは、同じロジックを複数の値(5つの商品、500件の注文、テーブルに含まれる任意の行数など)に連続して適用する方法です。同じコードブロックを何度もコピー&ペーストする必要はありません。

For...Next

決まった回数だけコードブロックを繰り返し実行します:

Dim i As Long
For i = 1 To 5
    Debug.Print "Row " & i
Next i
 
' Step lets you skip or count backward
For i = 10 To 1 Step -1
    Debug.Print i
Next i

最初のループでは、i1から始まり、その値で内部のコードが1回実行されます。その後、iは自動的に1ずつ増加し、ブロック全体が再度実行されます。i5を超えるまで繰り返され、超えた時点でループは停止し、Nextの後に処理が進みます。Stepで増分を変更できます:Step -1はデフォルトの1ずつ増加ではなく、1ずつ減少します。Step 2なら2ずつカウントします。ループ変数iは特別な構文ではなく、VBAが各ループごとに自動で更新する通常のLong型変数です。

For Each

コレクション内のすべての要素を直接ループ処理します。要素数やカウンターの管理は不要です:

Dim cell As Range
For Each cell In ThisWorkbook.Worksheets("Products").Range("B2:B6")
    Debug.Print cell.Value
Next cell

ここではcellが範囲B2:B6内の各セルを順番に受け取り、その中身を.Valueで取得します。For...Nextとの違いは、For...Nextでは数値でカウントし、その数値で何かを参照しますが、For Eachではアイテム自体を直接処理するため、ワークシート範囲を扱う際にはより直感的です。

Do While

条件がTrueである限り繰り返します。何回繰り返すかは事前には分かりません。これはFor...Nextとは異なります:

Dim stock As Integer
stock = 134
Do While stock > 0
    stock = stock - 30    ' simulate selling in batches of 30
Loop
Debug.Print stock   ' whatever's left after the loop stops

VBAは毎回ループの最初にstock > 0をチェックします。手作業で追ってみると:134 → 104 → 74 → 44 → 14、そして再度条件をチェックします。14はまだ0より大きいので、もう一度ループが実行され、-16になります。この時点でstock > 0がFalseとなり、ループは-16で終了します。0や14できれいに止まるわけではありません。初めて使う際は注意深く追跡する価値があります。Do Whileループは、条件がチェックされた時点で成り立つ限り繰り返されるため、ループ内の処理が意図した境界を超えてしまうことがよくあります。

Do Until

Do Untilもあり、これはDo Whileの逆です。条件がFalseの間繰り返し、条件がTrueになった瞬間に停止します。どちらが自然に読めるかは、ビジネスルールをどう表現するかによります。「在庫が残っている間続ける」ならDo While、「在庫がなくなるまで続ける」ならDo Untilです。どちらも同じ動作を実現できますが、表現の方向が異なります。

Exitステートメント

ループの終了条件に達する前に、途中でループを抜けることができます:

For i = 1 To 100
    If i = 10 Then Exit For   ' stop the loop immediately
    Debug.Print i
Next i

このループは本来100までカウントしますが、i10になった瞬間にExit Forで即座に終了します。Exit Forの後の処理は実行されず、Next iの次の行にジャンプします。リストを検索して目的のものが見つかった時点で処理を止めたい場合などに使います。

総まとめ

この章で学んだすべてのテクニック(変数、演算子、関数、条件分岐、そしてループ)は、以下の手続きで組み合わさっています:

Option Explicit
 
Sub CheckStockLevels()
 
    ' Sample data standing in for the Products table
    Dim products(1 To 5) As String
    Dim stockLevels(1 To 5) As Integer
    Dim reorderLevels(1 To 5) As Integer
    Dim i As Long
    Dim alertMessage As String
 
    products(1) = "Laptop Stand": stockLevels(1) = 58: reorderLevels(1) = 20
    products(2) = "Wireless Mouse": stockLevels(2) = 134: reorderLevels(2) = 30
    products(3) = "USB-C Hub": stockLevels(3) = 44: reorderLevels(3) = 15
    products(4) = "Monitor Arm": stockLevels(4) = 18: reorderLevels(4) = 10
    products(5) = "Keyboard": stockLevels(5) = 61: reorderLevels(5) = 20
 
    alertMessage = ""
 
    For i = 1 To 5
        Select Case stockLevels(i)
            Case Is <= reorderLevels(i)
                alertMessage = alertMessage & products(i) & _
                    " — REORDER NOW" & vbNewLine
            Case Is <= reorderLevels(i) + 10
                alertMessage = alertMessage & products(i) & _
                    " — watch closely" & vbNewLine
        End Select
    Next i
 
    If alertMessage = "" Then
        MsgBox "All products are adequately stocked."
    Else
        MsgBox "Stock Alerts:" & vbNewLine & alertMessage
    End If
End Sub
1行ずつの解説
expand arrow
  • Dim products(1 To 5) As Stringとその下の2行は配列の宣言です。各配列は5つのボックスが並んだ行で、products(1)が1つ目の商品名、products(2)が2つ目、というように使います。
  • コロン(:)で区切られた5行は、1行に複数の代入文をまとめて記述しています。products(1) = "Laptop Stand": stockLevels(1) = 58: reorderLevels(1) = 20は、3行に分けて書くのと全く同じ意味です。
  • For i = 1 To 5 ... Next iは5つの商品を1つずつ処理します。iはループカウンターであり、各配列のインデックスとしても使われます。
  • Select Case stockLevels(i)は、2.4節で紹介した範囲ベースの判定を、今度は実際の配列データに対して実行しています。
  • Case Is <= reorderLevels(i)は、在庫が再発注レベル以下になった商品を検出します。reorderLevels(i)自体が変数なので、各商品ごとに異なる基準値で判定されます。
  • alertMessage = alertMessage & ... & vbNewLineは、文字列を1行ずつ追加していきます。vbNewLineは改行を挿入する組み込み定数で、最終メッセージでは各商品が個別の行に表示されます。
  • 最後のIf alertMessage = "" Thenの判定で、どちらのMsgBoxを表示するかが決まります。空文字列なら、ループでフラグが立つ商品がなかったことを意味します。

これを実行すると、モニターアームが「watch closely」(在庫数18、再注文レベル10)としてフラグ付けされているのが確認できます。なぜ2番目のCaseでのみ検出され、最初のCaseでは検出されないのかを正確に確認したい場合は、i = 4でループを手作業で追跡してください。このプロシージャは、配列、ループ、Select Case、文字列構築を組み合わせて使用しています。これはすでに本番品質に近いロジックであり、実際のワークシートではなく、コード内に直接入力されたサンプルデータで動作しています。

課題

  1. CheckStockLevels をワークブックにコピーして実行し、メッセージがスクリーンショットと一致することを確認してください。
  2. ワイヤレスマウスの在庫を25に変更して再実行してください。今度は「watch closely」と表示されるはずです。
  3. その下に Do While ループを追加し、ラップトップスタンドの在庫が20以下になるまで一度に15個ずつ販売するシミュレーションを行い、各販売後に即時ウィンドウに累計を出力してください。
  4. チャレンジ:For i = 1 To 5 のループを、代わりにVariant配列に対して For Each を使って書き直してください。ロジックは依然として機能しますか?
ヒント
expand arrow

2. ワイヤレスマウスの在庫数の変更

  • ワイヤレスマウスのデータを設定している行を探します: products(2) = "Wireless Mouse": stockLevels(2) = 134: reorderLevels(2) = 30
  • 真ん中の数字(134)だけを25に変更します。商品名と発注点はそのままにします。
  • 実行前に、どのCaseが該当するか手計算で確認します: 25 ≤ 30(発注点)ですか?特にCase Is <= reorderLevels(i)の行と比較してください。2番目の行ではありません。

3. Do Whileによるバッチ販売のシミュレーション

  • ノートパソコンスタンドの在庫数を保持する変数が必要です。stockLevels(1)(58)と同じ値で開始します。これにより、マクロ内の他の値とずれないようにします。
  • ループ条件は在庫が20より大きいかどうかを確認します。在庫が20以下になった時点でループを終了します。
  • 1回ごとに15を減算し、減算後すぐに新しい値を出力します(減算前ではありません)。これにより、出力される各数値が販売後の在庫数を反映します。
  • 紙で追跡してみましょう: 58 → 43 → 28 → 13。最後の値が20を下回るのは、ちょうど20で止まらずにオーバーシュートするDo Whileの動作によるもので、バグではありません。これは本章のループ図でも説明されています。
解答例
expand arrow

ポイント2CheckStockLevels内で、1つの数字だけを変更します:

products(2) = "Wireless Mouse": stockLevels(2) = 25: reorderLevels(2) = 30

再度Subを実行します。

ポイント3 — 既存のコードの下に、まだCheckStockLevels内(End Subの前)で次を追加します:

    ' --- Simulate selling Laptop Stand in batches of 15 ---
    Dim laptopStandStock As Integer
    laptopStandStock = stockLevels(1)

    Do While laptopStandStock > 20
        laptopStandStock = laptopStandStock - 15
        Debug.Print laptopStandStock
    Loop
すべて明確でしたか?

どのように改善できますか?

フィードバックありがとうございます!

セクション 2.  5

AIに質問する

expand

AIに質問する

ChatGPT

何でも質問するか、提案された質問の1つを試してチャットを始めてください

セクション 2.  5
some-alt