【初心者向け】VBAでネスト(入れ子)の繰り返し処理を書く方法と注意点

A子さん

「えっ…Forの中にもう一つFor?
なんか見た目ややこしいし、これ絶対ミスるやつでしょ…?」

結論:ネストは“ループの中でさらにループ”する書き方。

表データの操作などにとても便利ですが、インデントと変数名に注意が必要です。

目次

ネスト(入れ子)とは?

ネストとは、「あるループの中に別のループを入れる構造」のことです。

正式には「ネストされたループ」や「入れ子構造のループ」と呼びます。VBAを本気で使い込み始めると、必ず遭遇する概念です。私も最初は「ちょっと複雑だな…」と敬遠していましたが、実務レベルの自動化を考えると避けて通れません。

For i = 1 To 3
    For j = 1 To 2
        Debug.Print "i=" & i & ", j=" & j
    Next j
Next i

このコードを実行すると、実際の動きは以下のようになります。

・iが1のとき、jは1から2まで全て実行
・iが2のとき、jはまた1から2まで全て実行
・iが3のとき、jはまた1から2まで全て実行

イメージとしては「外側のループが1回進むごとに、内側のループが全部まわる」という形になります。Debug.Printの出力結果は:

i=1, j=1
i=1, j=2
i=2, j=1
i=2, j=2
i=3, j=1
i=3, j=2

この「最初の1まわり中に、内側が複数回実行される」という動きが、ネストの本質です。

なぜネストが必要なのか

単純なループなら「For i = 1 To 10」で十分です。でも実務だと、「複数の列それぞれに対して、複数の行の処理をする」みたいな場面がごろごろあります。

例えば、Excelの表は本来「2次元」のデータ構造です。データは「行」と「列」の両方で配置されます。これを自動化処理するには、「行をループ」かつ「列もループ」する必要があります。その時に登場するのがネストです。

ネストなしでこれを実現しようとすると、複雑な計算式や条件分岐が増えて、かえってコードが読みづらくなる。だからネストは「2次元データを処理する標準的な書き方」として確立されているわけです。

典型的なネストの使い方:表を処理する

✅ 例:2行3列のセルに連番を入力する

Dim i As Integer, j As Integer
Dim num As Integer
num = 1

For i = 1 To 2 ' 行
    For j = 1 To 3 ' 列
        Cells(i, j).Value = num
        num = num + 1
    Next j
Next i

このコードを実行すると、以下のように連番がセルに入ります。

ABC
123
456

処理の流れを詳しく追ってみます。

i=1のとき:
j=1 → Cells(1,1)に1を入力 → numが2に増加
j=2 → Cells(1,2)に2を入力 → numが3に増加
j=3 → Cells(1,3)に3を入力 → numが4に増加
次のiへ

i=2のとき:
j=1 → Cells(2,1)に4を入力 → numが5に増加
j=2 → Cells(2,2)に5を入力 → numが6に増加
j=3 → Cells(2,3)に6を入力 → numが7に増加
終了

このように「行を1行ずつ進みながら、各行の中で列を1列ずつ進む」という2次元的な処理ができます。これがネストの最大の利点です。

実務での活用例

ネストの威力を実感するため、現実的なシナリオをいくつか紹介します。

📊 例1:複数の行をまとめて処理する

営業報告書が100行あり、各行に対して「売上」「原価」「利益」の3列を計算して、別シートに出力する。

この場合、外側のループで「100行をスキャン」し、内側のループで「3列の計算」をします。ネストなしでこれをやろうとすると、300個の計算式を手書きするハメになります。ネストなら10行で完了。

📋 例2:複数ファイルの複数シートを処理する

フォルダに10個のExcelファイルがあり、各ファイルに5個のシートがあり、それぞれのシートの特定セルを集計する。

この場合、「ファイルをループ」しながら「シートもループ」する3重ネストになることも。それでも書き方さえ正しければ、人間が100回手作業するより遥かに短時間で完了します。

🎯 例3:条件付きで複数セルを検索・更新する

A列の顧客ID「1001」に対応するB~E列の全データを更新する。複数の顧客がいるので「全行をスキャン」しながら「条件に合う列を処理」します。

このように、ネストは単なる「表に数字を入れる」だけじゃなく、実務の自動化で毎日活躍する書き方です。

よくあるミスと防ぎ方

ここではよくあるミスとその防ぎ方について紹介します。

❌ ミス1:インデントしないと可読性が地獄に…

For i = 1 To 3
For j = 1 To 3
Cells(i, j).Value = "○"
Next j
Next i
かもと

これ、どのNextがどのForに対応するのか、一瞬で分かりますか?

正直、読みづらいです。特にネストが3段4段になると、地獄です。

➡ インデント(字下げ)を行いましょう。

For i = 1 To 3
    For j = 1 To 3
        Cells(i, j).Value = "○"
    Next j
Next i

ぐっと読みやすくなりました。VBE(Visual Basic Editor)で [Tab] キーを使えば簡単にインデント可能です。複数行を選択してTab押下すれば、一括インデント。Shift+Tabで戻す。

実務では「インデント無しのコード」は「読みにくい= バグが隠れやすい = 後で修正しにくい」という悪循環になります。最初の数秒のインデント作業が、後々の時間を大きく節約します。

❌ ミス2:変数名の使い回し(本当に危険です)

For i = 1 To 3
    For i = 1 To 3 ' ←これ、地味に危険です
        Debug.Print "i=" & i
    Next i
Next i
A子さん

あ、外側のiと内側のiが同じ名前だ…何か起きそう。

その直感は正しいです。このコードを実行すると、外側のループが正常に動きません。なぜなら、変数iは「共有」されるからです。

内側のループが「Next i」を実行するたびに、変数iが上書きされます。外側のループのiまで影響を受けるんです。結果、ループが思わぬ回数で抜けたり、無限ループになったりします。

外側と内側で変数名を分ける(例:ijなど)

For i = 1 To 3
    For j = 1 To 3
        Debug.Print "i=" & i & ", j=" & j
    Next j
Next i

これなら、各変数が独立しています。外側のiが3回ループしている間、内側のjはそのたびに1から3まで全部ループします。

慣例として、外から順に「i」「j」「k」と命名するのが業界標準です。これに従っていれば、他の人がコードを読む時も「あ、3重ネストだな」と一瞬で把握できます。

❌ ミス3:Next文の対応を間違える

特に3重以上のネストになると、「このNext jはどのFor jに対応するのか?」という間違いが発生します。

For i = 1 To 3
    For j = 1 To 3
        For k = 1 To 3
            Debug.Print i & "," & j & "," & k
        Next k
    Next j
Next i

正しい形は「最後に開いたForから順番に閉じていく」(後入れ先出し)です。

VBEの「自動インデント機能」を有効にしていれば、自動的に対応が取られます。編集メニューの「自動インデント」をオンにしておくことをお勧めします。

❌ ミス4:ネストの深さをコントロールできていない

理論的には何重でも重ねられるネストですが、3重を超えるとコードの複雑さが爆発的に増えます。

i, j, k, l, m…と変数が増え、「あれ、この変数は何をカウントしてるんだっけ?」という状態になりやすい。

➡ そういう時は、処理を小分けにして「別の関数に分ける」という手があります。

Sub Main()
    For i = 1 To 3
        ProcessRow i
    Next i
End Sub
Sub ProcessRow(rowNum As Integer)
    For j = 1 To 3
        For k = 1 To 3
            Debug.Print rowNum & "," & j & "," & k
        Next k
    Next j
End Sub

こうすることで「メインルーチンは行だけをループ」し、「各行の詳細処理は関数に委譲」という構造になります。結果、各関数が理解しやすくなり、バグも減ります。

応用:条件付きで内側ループをスキップ

ネストの基本が分かったら、次は「特定の条件でループをスキップする」という応用に進みます。

IfExit For を組み合わせれば、柔軟な処理が可能です。

For i = 1 To 5
    For j = 1 To 5
        If j = 3 Then
            Exit For ' jが3ならループを抜ける
        End If
        Debug.Print "i=" & i & ", j=" & j
    Next j
Next i

このコードを実行すると、jが3に達した時点で内側のループを抜けて、次のiに移ります。

出力は以下のようになります。

i=1, j=1
i=1, j=2
i=2, j=1
i=2, j=2
i=3, j=1
i=3, j=2
i=4, j=1
i=4, j=2
i=5, j=1
i=5, j=2

各iにおいて、j=3になったら即座に内側ループを抜けているのが分かります。

関連:外側ループも一緒に抜けたい場合

もし「j=3に達したら、外側のiループも一緒に抜けたい」という場合は、フラグを使います。

Dim exitFlag As Boolean
exitFlag = False

For i = 1 To 5
    For j = 1 To 5
        If j = 3 Then
            exitFlag = True
            Exit For
        End If
        Debug.Print "i=" & i & ", j=" & j
    Next j
    
    If exitFlag Then
        Exit For ' 外側ループも抜ける
    End If
Next i

このように「フラグ変数」を使うことで、ネストの外側の層にも情報を伝達できます。

ネストの処理速度について

「ネストは遅くないか?」という質問をよく受けます。

答え:ネスト自体は遅くありません。ただし「ループの回数」が増えるので、回数が多いと遅くなります。

例えば、100行×100列のセルに値を入力する場合、10,000回のループが必要です。そこに「セルの計算」や「別シートへのアクセス」が入ると、さらに遅くなります。

大量データを扱う場合は、以下の工夫が有効です。

⚡ 工夫1:画面更新を止める

Application.ScreenUpdating = False

For i = 1 To 1000
    For j = 1 To 100
        Cells(i, j).Value = i * j
    Next j
Next i

Application.ScreenUpdating = True

ScreenUpdatingをFalseにすると、ループ中の画面描画が止まり、速度が大幅に向上します。

⚡ 工夫2:計算を自動計算から手動計算に切り替える

Application.Calculation = xlManual

For i = 1 To 1000
    For j = 1 To 100
        Cells(i, j).Value = i * j
    Next j
Next i

Application.Calculate
Application.Calculation = xlAutomatic

Excelがループ中に毎回計算をするのを防ぎ、最後にまとめて計算させることで高速化できます。

ネスト vs 配列:どっちを使う?

VBAを続けていると、「Arrayを使った処理」という別の方法に出会います。大量の列データを一度に配列に読み込んで、ループで処理する方法です。

「ネストと配列、どっち使う?」というのは、頻出の質問です。

目安:
・数百行程度、計算が軽い → ネストで十分
・数千行以上、複雑な計算 → 配列の方が高速
・小規模な表操作、わかりやすさ重視 → ネスト
・パフォーマンス重視 → 配列

実務では「最初はネストで書いて、遅かったら配列に変える」というやり方が現実的です。必要になるまで、無理に配列にする必要はありません。

よくあるつまずきポイント

🤔 Q1:ネストが上手くいかない。何が間違ってるのか分からない。

A:Debug.Printを大活用しましょう。ループの各段階で「iとjの値は何か」を出力して、期待と一致するか確認します。

For i = 1 To 3
    Debug.Print "i=" & i & " (外側ループ開始)"
    For j = 1 To 3
        Debug.Print "  j=" & j & " (内側実行中)"
    Next j
    Debug.Print "i=" & i & " (外側ループ終了)"
Next i

イミディエイトウィンドウに出力されるDebug.Printの値を眺めれば、ループがどう動いているかが明確になります。

🤔 Q2:ネストの中で、配列やコレクションにアクセスしたい。

A:完全に可能です。むしろ、セル直接アクセスより高速です。

Dim data As Variant
data = Range("A1:C3").Value

For i = 1 To 3
    For j = 1 To 3
        Debug.Print data(i, j)
    Next j
Next i

Cells(i,j)のような遅いセルアクセスより、配列経由の方がずっと高速です。

🤔 Q3:ネストを途中で抜ける時、全部抜けたいのに内側だけ抜けてしまう。

A:先ほど説明した「フラグ方式」で対応します。または、ネストごと別関数に分割して、関数をExit Subで抜けるのも手です。

実践的な例:成績表を作成する

最後に、ネストを使った実践的な例をご紹介します。

シナリオ:10人の学生の、5科目の成績が入力されている。合計点と平均点を計算して、隣の列に出力したい。

Sub CalculateScores()
    Dim i As Integer, j As Integer
    Dim sum As Integer
    Dim avg As Double
    
    ' A列:学生名、B列~F列:5科目の成績
    ' G列:合計、H列:平均
    
    Application.ScreenUpdating = False
    
    For i = 2 To 11 ' 2行目から11行目(学生データ)
        sum = 0
        
        For j = 2 To 6 ' B列から F列(5科目)
            sum = sum + Cells(i, j).Value
        Next j
        
        avg = sum / 5
        
        Cells(i, 7).Value = sum ' G列に合計
        Cells(i, 8).Value = avg ' H列に平均
    Next i
    
    Application.ScreenUpdating = True
    MsgBox "計算が完了しました"
End Sub

このコードは「外側のループで各学生を処理」し、「内側のループで各学生の5科目を合計」しています。10人 × 5科目 = 50回の処理が自動実行されます。

まとめ:ネストを使いこなすコツ

  • ネストは「2次元的な処理」に最強。表データの自動化なら避けられない。
  • インデント
  • 変数名を分ける
  • Next文は「最後に開いたForから順番に」閉じる。
  • ネストが3重を超えたら、関数に分割することを検討。
  • Debug.Printで各段階の値を確認。何が起きてるか可視化する。
  • 大量データの場合は、ScreenUpdatingとCalculationの設定で高速化。
かもと

ネストはVBAの「基本の基本」ですが、ここを正確に理解していると、後々の複雑な処理がグッと分かりやすくなります。インデント・変数名・構造の3つを意識するだけで、グンと書きやすくなりますよ。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

かもろぐ屋へようこそ。

Microsoft製品が大好きな現役社内SEです。
本業では、業務改善・運用・トラブル対応・効率化など、いわゆる「社内の困った」を何でも屋のように対応しています。

このブログでは主に、

VBA
Power Apps
AI

について、実体験ベースで発信しています。

特に最近は、AIを使ったアプリ開発やブログ運営の自動化にハマっています。
「AIがあれば簡単に作れる」と思って始めた結果、普通に壊れたり、詰んだり、課金したりしながら泥臭く進めています。

キラキラした成功談というより、

「実際どうだったのか」
「どこで詰まったのか」
「初心者でも本当にできるのか」

を、できるだけリアルに残すタイプのブログです。

なお、絶賛婚活中です。

コメント

コメントする

CAPTCHA


目次