If 文で複数の条件を組み合わせる際に使用する And(かつ)と Or(または)。1つの If 条件式の中に両方が混在している場合、どちらが優先して評価されるかという「論理演算子の優先順位構造」を正しく把握しておく必要があります。
1. 問題:And と Or が混在する条件式の評価
【 問題 】 下記のコードを実行して CheckLogic プロシージャを呼び出した際、メッセージボックス(MsgBox)に表示される文字列として正しいものはどれでしょうか?
Sub CheckLogic()
Dim age As Integer
Dim member As Boolean
Dim coupon As Boolean
age = 25
member = False
coupon = True
If age >= 60 Or member = True And coupon = True Then
MsgBox "割引適用"
Else
MsgBox "通常料金"
End If
End Sub
① 割引適用
② 通常料金
③ 条件式の構文エラー(コンパイルエラー)が発生する
④ 実行時エラーが発生する
2. 正解:And と Or の評価順序に関する正解
3. 解説:「And 優先」で評価される論理演算の構造
VBAの仕様上、かっこ ( ) を使っていない場合、「And は Or よりも優先して先に計算される」という明確な優先順位ルールが存在します。
[ 条件式の評価構造ステップ ]
元の条件式:age >= 60 Or member = True And coupon = True
1. 優先度の高い And を先に結合・評価:
(member = True And coupon = True) の部分が先に判定されます。
・member は False
・coupon は True
⇒ False And True の結果は False となります。
2. 残った Or を評価:
age >= 60 Or [ステップ1の結果(False)] を判定します。
・age >= 60 (25 >= 60) は False
⇒ False Or False の結果は最終的に False となります。
★ したがって、If ブロックは実行されず、Else 側の "通常料金" が出力されます。
ここが試験に出る!: スタンダード試験では、「左から順番に Or から計算してしまう」という勘違いを誘う問題が頻出します。もし「(60歳以上または会員)であり、かつクーポンを持っている」という条件にしたい場合は、(age >= 60 Or member = True) And coupon = True のようにカッコで囲んで意図的に優先順位を変える必要があります。
4. まとめ
「And は掛け算(優先度高)、Or は足し算(優先度低)と同じ感覚で評価される」。この演算子の優先順位構造を頭に入れておけば、実務で複雑な顧客条件分岐やエラー判定ロジックを組む際にも、予期せぬ判定ミスを回避できます。
PR
VBAの条件分岐の基本である If ... Then ... Else ... End If。複数の条件を評価する ElseIf や分岐の入れ子(ネスト)構造において、プログラムがどのような順番で条件を評価し、どの処理を通過するかを正しく読み解きましょう。
1. 問題:If ... Then ... ElseIf の評価順序と実行結果
【 問題 】 下記のコードを実行して EvaluateScore プロシージャを呼び出した際、メッセージボックス(MsgBox)に表示される文字列として正しいものはどれでしょうか?
Sub EvaluateScore()
Dim score As Integer
score = 85
If score >= 70 Then
MsgBox "合格"
ElseIf score >= 80 Then
MsgBox "優秀"
Else
MsgBox "不合格"
End If
End Sub
① 合格
② 優秀
③ 合格 と 優秀 の両方が表示される
④ 構文エラー(コンパイルエラー)が発生する
2. 正解:If文の分岐評価に関する正解
3. 解説:条件が「上から順番に評価される」構造の罠
If ... ElseIf 構造では、条件式が上から順番に判定され、最初に条件を満たした(Trueになった)ブロックの処理だけが実行されるという厳格なルールがあります。
[ If 分岐の実行フロー構造 ]
変数:score = 85
1. 1つ目の条件判定(If score >= 70):
85 >= 70 は 成立(True!)
⇒ MsgBox "合格" が実行される!
2. 2つ目以降の判定(ElseIf score >= 80):
すでに最初の条件で True になったため、2つ目以降の条件式は判定すらされずにスキップされ、End If の直後へ抜けます。
★ score = 85 は「80以上(優秀)」の条件も満たしていますが、先に「70以上(合格)」にヒットしてしまうため、「優秀」が表示されることはありません。
ここが試験に出る!: スタンダード試験では、このように「条件の記述順序ミス(評価の逆転)」を突く問題が非常によく出題されます。「優秀(80以上)」を正しく判定させたい場合は、If score >= 80 Then を一番上に書かなければならないという判定ロジックの構造を押さえておきましょう。
4. まとめ
「If文は最初につかまった条件で終了し、以降のElseIfは無視される」。この評価順序の仕組みを理解しておけば、実務で多段階の成績判定や金額の割引率計算を実装する際にも、条件の並べ順ミスによるロジックバグを完璧に防げるようになります。
For Each ... Next はワークシートやセル範囲だけでなく、「配列」の全要素を一括処理する際にも頻繁に使用されます。配列を走査する際の変数宣言(データ型)のルールをマスターしましょう。
1. 問題:配列に対する For Each の要素変数の型
【 問題 】 下記の ArrayLoopTest プロシージャを実行し、配列の要素を1つずつメッセージボックスに表示したい。空欄 ( A ) に入る要素変数のデータ型として、文法上**正しいもの**はどれでしょうか?
Sub ArrayLoopTest()
Dim arr As Variant
Dim item As ( A )
arr = Array("Tokyo", "Osaka", "Nagoya")
For Each item In arr
MsgBox item
Next item
End Sub
① String
② Variant
③ Object
④ Array
2. 正解:配列に対する要素変数の型に関する正解
3. 解説:配列を For Each で回す際の厳格な構文ルール
For Each ... Next を配列(Array)に対して使用する場合、VBAには言語仕様上の明確な制約が存在します。
[ 配列×For Each の構文ルール ]
・要素変数(item)は必ず Variant 型にする必要がある
たとえ配列の中身がすべて文字列(String型)であっても、For Each item In arr の要素変数 item は Variant 型(または型指定なしの標準Variant)で宣言しなければなりません。
・なぜ String 型(①)ではエラーになるのか?
VBAの仕様上、配列を For Each で受ける変数には Variant 型または Object 型しか認められていません。Dim item As String と記述すると、実行時に「変数の型が一致しません(コンパイルエラー)」が発生します。
ここが試験に出る!: スタンダード試験では、「中身が文字列だから As String で受けられる」という勘違いを狙うトラップ問題が非常に多く出題されます。「コレクション(WorksheetsやRange)なら特定の型(WorksheetやRange)が使えるが、配列のFor Eachは Variant型 が必須」という構造の違いを必ず暗記しておきましょう。
4. まとめ
「配列を For Each で受ける変数は Variant 一択」。このルールさえ覚えておけば、実務で `Array` 関数で作ったリストや動的配列の全要素チェックを行う際にも、コンパイルエラーを起こさずにスムーズなループ処理が実装できます。
データ入力チェックや未入力セルのカウントなどで頻出するのが、For Each ... Next を使ってセル範囲内の空白セルを1つずつ判定する処理です。空白の判定構文と集計のフローをマスターしましょう。
1. 問題:空白セルの判定とカウント処理
【 問題 】 下記の図のように、Excelシートの A1:B3 のセルに値(一部は空欄)が入力されています。この状態で以下の CountBlankCells プロシージャを実行した際、メッセージボックス(MsgBox)に表示される数値として正しいものはどれでしょうか?
| A | B |
| 1 |
100 |
(空白) |
| 2 |
(空白) |
200 |
| 3 |
300 |
(空白) |
Sub CountBlankCells()
Dim rng As Range
Dim c As Range
Dim blankCount As Long
Set rng = Range("A1:B3")
blankCount = 0
For Each c In rng
If c.Value = "" Then
blankCount = blankCount + 1
End If
Next c
MsgBox blankCount
End Sub
① 2
② 3
③ 6
④ 構文エラー(コンパイルエラー)が発生する
2. 正解:実行結果
3. 解説:空白セルの判定構造とトレース
Range("A1:B3") の全6セルを For Each で1セルずつ巡回し、値が空文字("")であるかを判定していきます。
【各セルの処理ステップ(左から右、上から下への順)】
初期値: blankCount = 0
1. セル A1(値: 100) : 100 = "" は False → 加算しない
2. セル B1(値: 空白): "" = "" は True → blankCount = 0 + 1 = 1
3. セル A2(値: 空白): "" = "" は True → blankCount = 1 + 1 = 2
4. セル B2(値: 200) : 200 = "" は False → 加算しない
5. セル A3(値: 300) : 300 = "" は False → 加算しない
6. セル B3(値: 空白): "" = "" は True → blankCount = 2 + 1 = 3
★ 合計3つの空白セルが検出され、メッセージボックスには 3 が表示されます。
ここが試験に出る!: スタンダード試験では、空白セルの判定として If c.Value = "" Then のほかに、If IsEmpty(c.Value) Then や If Len(c.Value) = 0 Then などの構文もよく出題されます。いずれの書き方でも「値が入っていないセル」を判定する仕組みをしっかり整理しておきましょう。
4. まとめ
「セル範囲をFor Eachで巡回し、c.Value = "" でカウントする」。この基本パターンを押さえておけば、実務での未入力チェックや、入力漏れのあるセルへの警告メッセージ表示などを簡単に作成できるようになります。
| A | B |
| 1 |
100 |
(空白) |
| 2 |
(空白) |
200 |
| 3 |
300 |
(空白) |
Sub CountBlankCells()
Dim rng As Range
Dim c As Range
Dim blankCount As Long
Set rng = Range("A1:B3")
blankCount = 0
For Each c In rng
If c.Value = "" Then
blankCount = blankCount + 1
End If
Next c
MsgBox blankCount
End Sub
① 2
② 3
③ 6
④ 構文エラー(コンパイルエラー)が発生する
2. 正解:実行結果
3. 解説:空白セルの判定構造とトレース
Range("A1:B3") の全6セルを For Each で1セルずつ巡回し、値が空文字("")であるかを判定していきます。
【各セルの処理ステップ(左から右、上から下への順)】
初期値: blankCount = 0
1. セル A1(値: 100) : 100 = "" は False → 加算しない
2. セル B1(値: 空白): "" = "" は True → blankCount = 0 + 1 = 1
3. セル A2(値: 空白): "" = "" は True → blankCount = 1 + 1 = 2
4. セル B2(値: 200) : 200 = "" は False → 加算しない
5. セル A3(値: 300) : 300 = "" は False → 加算しない
6. セル B3(値: 空白): "" = "" は True → blankCount = 2 + 1 = 3
★ 合計3つの空白セルが検出され、メッセージボックスには 3 が表示されます。
ここが試験に出る!: スタンダード試験では、空白セルの判定として If c.Value = "" Then のほかに、If IsEmpty(c.Value) Then や If Len(c.Value) = 0 Then などの構文もよく出題されます。いずれの書き方でも「値が入っていないセル」を判定する仕組みをしっかり整理しておきましょう。
4. まとめ
「セル範囲をFor Eachで巡回し、c.Value = "" でカウントする」。この基本パターンを押さえておけば、実務での未入力チェックや、入力漏れのあるセルへの警告メッセージ表示などを簡単に作成できるようになります。
"
dc:identifier="http://rikeineo.blog.shinobi.jp/Entry/2170/" />
-->
ブック内のすべてのシートに対して同じ処理を繰り返し実行したい時に活躍するのが For Each ... Next です。コレクションからオブジェクトを1つずつ取り出す際の、正しい変数宣言と構文構造をマスターしましょう。
1. 問題:Worksheetsコレクションに対する For Each の指定方法
【 問題 】 アクティブブック内のすべてのワークシートの名前をイミディエイトウィンドウに出力したい。空欄 ( A ) に入る記述として、文法上**誤っている**(エラーになる)ものはどれでしょうか?
Sub SheetNameList()
Dim ( A )
For Each ws In Worksheets
Debug.Print ws.Name
Next ws
End Sub
① ws As Worksheet
② ws As Variant
③ ws As Object
④ ws As Worksheets
2. 正解:For Each の要素変数宣言に関する正解
3. 解説:「単数形(要素)」と「複数形(集合)」の構造的な違い
For Each ... Next では、取り出す「中身(要素)」と全体の「集まり(コレクション)」の型を正しく区別して定義する必要があります。
[ For Each の変数宣言構造 ]
構文:For Each [要素変数] In [コレクション]
・要素変数(ws)の型ルール
取り出すのは「シート1枚(単体)」なので、単体を表す Worksheet型(①)、またはあらゆるオブジェクト・値を受け取れる Variant型(②)、汎用オブジェクトの Object型(③)を指定する必要があります。
・誤り(④)の理由
Worksheets(複数形)はシートの「集まり(コレクション)」を表す型です。1枚のシートを受け取る変数 ws に対してコレクション型を指定することはできないため、データ型の不一致エラー(コンパイルエラー)が発生します。
ここが試験に出る!: スタンダード試験では、For Each ws In Worksheets のように要素変数(単数形の Worksheet)とコレクション(複数形の Worksheets)の「sのあるなし」をひっかけとして出してきます。また、Sheets コレクション(グラフシートも含む)を処理する場合の型の選び方についても正確に押さえておきましょう。
4. まとめ
「取り出す変数には単体(Worksheet)を指定し、In の後ろには集合(Worksheets)を指定する」。この単数形と複数形の構造ルールを意識しておけば、全シートの一括処理や非表示シートの自動判定など、実務で強力な一括制御マクロを迷わず書けるようになります。