🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

Excel VBA の Intersect — 2 つの範囲が重なる場所を見つける(そして誰もが使う Worksheet_Change のガード)

|

Excel VBA の Intersect — 2 つの範囲が重なる場所を見つける(そして誰もが使う Worksheet_Change のガード)

TL;DRIntersect は、2 つの範囲が共有するセルだけを返します。触れ合わなければ Nothing を返します — 空の範囲でもエラーでもなく — そしてその Nothing こそが肝心な点 です。一番の用途は Worksheet_Change イベントをガードして、気にかける列の編集にだけ反応 させることです。最も大事なルール:重なりがなければ Nothing なので、Is Nothing の確認 なしにどんなプロパティへ触れても error 91 でクラッシュします。

Private Sub Worksheet_Change(ByVal Target As Range)
    If Intersect(Target, Me.Range("B:B")) Is Nothing Then Exit Sub   ' 編集は B 列ではなかった
    Application.EnableEvents = False                                  ' 自分の書き込みでこれが再発火しないように
    Target.Offset(0, 1).Value = Now                                  ' 隣に時刻を刻む
    Application.EnableEvents = True
End Sub

Union は範囲をまとめます。Intersect はその正反対で — 共有部分へ縮めます。そして それ以前のどの参照とも違い、Intersectまったく何も返さないことが正当にありえます。 重ならない 2 つの範囲には共通のセルがないからです。本記事は 1 つの考えを軸にしています。 Intersect は「これらは重なるか?」という yes/no の問いに、重なりか Nothing のどちらかを 返して答える。だから触れる前に、どちらなのかを判定しなければならない。 その 1 つの習慣が、 堅牢なイベントハンドラーと、間違ったクリックでクラッシュするものとを分けます。

この記事で学べること

  • 考え方の軸 — Intersect は 2 つの範囲の重なり、外れれば Nothing を返す
  • 最も大事なルール — 重なりがなければ Nothing、だから Is Nothing でガードしないと error 91
  • 決定的な用途 — Worksheet_Change のガードと、それに付いてくる EnableEvents の罠
  • Intersect(Selection, ...) でマクロを対象エリアに限定する
  • なぜ Intersect(∩、重なり)は Union(∪、まとめる)の正反対なのか
  • 複数範囲の Intersect と、同じシートのルール

考え方の軸:Intersect は 2 つの範囲の重なり

Intersect に 2 つの範囲を渡すと、両方にあるセルだけへの参照を返します。

Dim shared As Range
Set shared = Intersect(Range("A1:D10"), Range("C5:F20"))
' shared は C5:D10 - 2 つの範囲が共通して持つ長方形

2 つの範囲が何も共有しなければ、返すべき共通の長方形がないので、IntersectNothing を 返します。それこそが、これを便利にする振る舞いです。重なりのセルそのものを気にかけることは めったになく、そもそも重なりがあるかどうかを気にかけるのです。「このセルはあの領域の中に あるか?」は、「Intersect(cell, region)Nothing ではなく何かか?」になります。Intersect は幾何の問いを、単純な有無の判定に変えます。

最も大事なルール:重なりがなければ Nothing が返る

外れると Nothing が返るので、確認せずに結果に対してどんなプロパティやメソッドへ手を 伸ばしても、それはクラッシュ待ちです。

' 脆い書き方 - 範囲が重ならない瞬間に error 91:
MsgBox Intersect(Selection, Range("B:B")).Address

Selection が B 列にないとき、IntersectNothing で、Nothing に対する .Addresserror 91「オブジェクト変数または With ブロック変数が設定されていません」を発生させます。 修正は必ず Is Nothing で先に判定することで、慣用的な言い回しは「重なりがあるなら」を 意味する If Not ... Is Nothing を使います。

If Not Intersect(Selection, Range("B:B")) Is Nothing Then
    MsgBox "Your selection touches column B."
End If

If Not (重なり) Is Nothing は「重なりが Nothingないなら」— つまり、それが存在するなら — と読みます。ここでの 2 つの間違いは、Not を落とすこと(論理が反転する)と、Is Nothing の 確認を落とすこと(外れたときクラッシュする)です。この一節を丸ごと覚えましょう。VBA 全体でも 最も多く打たれる行の 1 つです。

決定的な用途:Worksheet_Change のガード

ここで Intersect はその存在価値を示します。Worksheet_Change イベントは、シート上のどこ の編集でも発火し、99% の場合、あなたは 1 つの列や領域の変更にだけ反応したいはずです。ガードが なければ、ハンドラーはシート全体のあらゆるキー入力で走ります — 遅くて邪魔です。Intersect が そのガードです。変更されたセル(Target)が、監視している範囲と重なるかを尋ねます。

Private Sub Worksheet_Change(ByVal Target As Range)
    ' 編集がデータ範囲 B2:B1000 に入ったときだけ動く:
    If Intersect(Target, Me.Range("B2:B1000")) Is Nothing Then Exit Sub

    Application.EnableEvents = False          ' 重要 - 下記参照
    On Error GoTo CleanExit
    Dim c As Range
    For Each c In Intersect(Target, Me.Range("B2:B1000")).Cells
        c.Offset(0, 1).Value = "edited " & Format(Now, "yyyy-mm-dd hh:nn")
    Next c

CleanExit:
    Application.EnableEvents = True           ' エラーのあとでも必ず戻す
End Sub

これを正しいパターンにしているのは 2 つです。第一に、ガード行 If Intersect(...) Is Nothing Then Exit Sub が、対象の外のどんな編集でも早々に抜けるので、本体は走るべきときにだけ走ります。 第二に — そしてこれが誰もを捕まえる罠ですが — ハンドラーはセルへ書き込み、セルへの書き込みは Worksheet_Change再び発火させ、それがまた書き込み、と続きます。Application.EnableEvents = False がその再帰を断ち切り、それは CleanExit ラベルの中で戻さねばなりません。さもないと ハンドラー途中のエラーが、そのセッションの残りずっとイベントを無効のまま残します(VBA On ErrorWorksheet_Change を参照)。Intersect のガードと EnableEvents のガードは兄弟です — 片方だけが欲しいことは、まずありません。

マクロを対象エリアに限定する

同じ重なりの判定は、普通のマクロを 1 つの領域に絞ります。ある書式設定マクロが、ユーザーが 印刷範囲の中で選んだセルだけに触れるべきだとします — 選択と領域を intersect し、その結果を 操作します。

Dim scope As Range
Set scope = Intersect(Selection, Range("PrintArea"))
If scope Is Nothing Then
    MsgBox "Select cells inside the print area first."
    Exit Sub
End If
scope.Font.Bold = True   ' PrintArea の中に入る、選択されたセルだけ

これは、選択された各セルのアドレスを手で確かめるより、すっきりしたパターンです。Intersect が 範囲内の部分集合を 1 回の呼び出しで計算し、Is Nothing の分岐が「選択が領域を丸ごと外した」を 処理します。

Intersect と Union:重なり vs まとめる

Intersect(∩)と Union(∪)は、範囲に対する 2 つの集合演算子で、 正反対の方向へ引きます。Union(A, B) は、どちらかの範囲にあるすべてへ参照を大きくします。 Intersect(A, B) は、両方にあるものだけ、または Nothing へ小さくします。Union は決して Nothing を返しません(組み合わせる実在の範囲を渡したのですから)。Intersect はしょっちゅう Nothing を返し、それは欠陥ではなく持ち味です。散らばったセルをバッチ操作のために組み立てる には Union、編集・選択・セルが気にかける領域の中に入るかを判定したり制限したりするには Intersect を使いましょう。

複数範囲の Intersect と、同じシートのルール

Intersect は 2 つより多くの範囲を受け取り、それらすべてに共通するセルを返します — Intersect(rngA, rngB, rngC) は、どの引数も覆う領域です。Union と同じく、すべての範囲は 同じワークシート上になければならず、さもないと error 1004 になります。そして同じ流儀が 結果にも当てはまります。重なりが空になりうるなら、使う前に Is Nothing を判定しましょう — 3 つ以上の範囲では、空の重なりは 2 つのときよりもさらに起こりやすいのです。

ExcelMaster の活用

Intersect は小さなメソッドですが、忘れやすい 2 つのルールを隠しています。結果に触れる前に Is Nothing を確認すること、そしてイベントのガードを EnableEvents = False と組にして、自分で 引き起こした変更が暴走しないようにすること。前者を忘れれば error 91 でクラッシュし、後者を 忘れれば Worksheet_Change ハンドラーが自分自身を再発火させ、ちらつきやハングになります。

ExcelMaster なら、代わりに 振る舞いを述べるだけで済みます。「誰かが B 列を編集したら、C 列に時刻を刻んで」と言えば、 Intersect(Target, ...) のガード、早期の Exit SubEnableEvents の切り替え、CleanExit の 復元を書いてくれます — ハッピーパスだけでなく、堅牢なイベントパターン全体です。ブックも コードもあなたの手元に残り、ハンドラーが間違ったセルで発火した、あるいは自分自身をループした、 あのデバッグを飛ばせます。

よくある質問

Excel VBA の Intersect メソッドは何をしますか?

Intersect は、2 つ以上の範囲が共通に持つセル — その重なり — の範囲を返します。 Intersect(Range("A1:D10"), Range("C5:F20")) は C5:D10 を返します。範囲がまったく重ならなければ IntersectNothing を返し、だからこそ、ある範囲が別の範囲の中に入るかを判定するのに 使われます。

なぜ Intersect は Nothing を返してコードをクラッシュさせるのですか?

範囲がセルを 1 つも共有しないとき、Intersect は空の範囲ではなく Nothing を返します。その あと、それに対するどんなプロパティ — .Address.Cells.Value — へ触れても error 91 が 発生します。使う前に必ず If Not Intersect(a, b) Is Nothing Then(「重なりがあるなら」の意味)で 先に判定しましょう。

Worksheet_Change イベントで Intersect をどう使いますか?

ハンドラーをガードして、対象範囲の中の編集にだけ反応させます。 If Intersect(Target, Me.Range("B2:B1000")) Is Nothing Then Exit Sub です。それから、どのセルへ 書き込む前にも Application.EnableEvents = False を設定し — さもないと書き込みが Worksheet_Change を再び引き起こします — CleanExit ラベルの中で True に戻して、エラーがイベントを無効のまま 残せないようにします。

VBA で Intersect と Union の違いは何ですか?

正反対の集合演算です。Intersect両方の範囲にあるセルだけ(重なり)、触れ合わなければ Nothing を返します。Unionどちらかの範囲にあるセル(合わさった領域)を返します。 ある領域を判定したり制限したりするには Intersect、散らばったセルを 1 つの参照に組み立てるには Union を使いましょう。

Intersect は 2 つより多くの範囲を取れますか?

はい。Intersect(rngA, rngB, rngC) は、範囲すべてに共通するセルを返します。すべての範囲は 同じワークシート上になければならず、範囲が共通のセルを共有しなければ結果は Nothing になりえます — これは 3 つ以上の範囲でより起こりやすいので、必ず Is Nothing を確認しましょう。

検証環境

検証環境: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-08-16。

関連ガイド: VBA Union · VBA SpecialCells · VBA Worksheet_Change · VBA On Error · VBA Range