- 技術 💻
VBA Findの使い方とAutoFilter抽出|複数条件のコード集
VBAでセルを探すときは、1件探すなら Find、全件拾うなら FindNext を最初の Address に戻るまで回し、条件に合う行をまとめて写すなら AutoFilter を使います。 どれも Range オブジェクトのメソッドで、引数の指定のしかたと「見つからなかったとき」の分岐を押さえれば、同じ形で使い回せます。
この記事では、Find・FindNext・AutoFilter のコピーして使えるコードに加えて、「あるはずの値が見つからない」原因の一覧表、複数条件(AND・OR・3つ以上・日付)の書き方、該当0件のときの分岐までをまとめます。
確認環境:Microsoft Learn の Excel VBA リファレンス(Range.Find、Range.FindNext、Range.AutoFilter、XlAutoFilterOperator、Range.SpecialCells、Range.Copy、WorksheetFunction.Match ほか)を 2026-10-05 に開き、メソッド・引数・注意書きを確認してコードを書いています。「出力」を付けたコード(Find の1件検索、部分一致と完全一致、Nothing のまま使ったときのエラー番号、配列走査)と、AutoFilter の一部(条件1つ、同じ列の AND・OR、日付の範囲、0件の判定)は、LibreOffice 24.2.7.2 の Basic(VBA 互換モード、Option VBASupport 1)で動かして確かめました。
この記事の結論
- 1件探すなら Find。戻り値は Range で、見つからないと Nothing が返るので、使う前に必ず
Is Nothingで分岐します。 - 全件拾うなら FindNext。検索は範囲の終わりから先頭へ折り返すので、最初に見つけたセルの Address を控え、同じ Address に戻ったら終えます。
- 条件に合う行をまとめて写すなら AutoFilter。絞り込んだあと、見えているセルだけを別シートへコピーします。
- Find の LookIn・LookAt・SearchOrder・MatchByte は前回の指定が残ります。毎回すべて書くのが、いちばん確かな対処です。
Find・FindNext・AutoFilterの判断表
| やりたいこと | 使うもの | 終わり方・0件のとき |
|---|---|---|
| 最初の1件の位置を知りたい | Range.Find |
見つからないと Nothing |
| 同じ値のセルを全部拾いたい | Range.Find + Range.FindNext |
最初の Address に戻ったら終了 |
| 条件に合う行を別シートへ写したい | Range.AutoFilter + SpecialCells(xlCellTypeVisible) |
見えているセルの数で0件を判定 |
| 1列の中で何番目にあるか知りたい | Application.Match |
見つからないとエラー値(IsError で判定) |
| 複数列の条件を細かく組み合わせたい | 配列に読み込んで For で走査 | 件数の変数が 0 のまま |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「VBA Findの使い方とAutoFilter抽出|複数条件のコード集」
サンプルデータを用意する
以降のコードは、Sheet1 に次の表があり、抽出先として Sheet2 がある前提です。MakeSample を実行すると Sheet1 に同じ表が作られます。
| A | B | C | D | |
|---|---|---|---|---|
| 1 | 日付 | 部署 | 品名 | 数量 |
| 2 | 2026/4/1 | 総務 | ノート | 10 |
| 3 | 2026/4/3 | 営業 | ペン | 24 |
| 4 | 2026/4/10 | 開発 | ノート | 5 |
| 5 | 2026/4/15 | 総務 | 付箋 | 8 |
| 6 | 2026/5/2 | 営業 | ノート | 12 |
| 7 | 2026/5/9 | 開発 | 電池 | 4 |
| 8 | 2026/5/20 | 総務 | ペン | 6 |
| 9 | 2026/6/1 | 営業 | ファイル | 30 |
Sub MakeSample()
Dim ws As Worksheet, i As Long, items As Variant
Set ws = Worksheets("Sheet1")
ws.AutoFilterMode = False
ws.Cells.Clear
ws.Range("A1:D1").Value = Array("日付", "部署", "品名", "数量")
items = Array( _
Array(DateSerial(2026, 4, 1), "総務", "ノート", 10), _
Array(DateSerial(2026, 4, 3), "営業", "ペン", 24), _
Array(DateSerial(2026, 4, 10), "開発", "ノート", 5), _
Array(DateSerial(2026, 4, 15), "総務", "付箋", 8), _
Array(DateSerial(2026, 5, 2), "営業", "ノート", 12), _
Array(DateSerial(2026, 5, 9), "開発", "電池", 4), _
Array(DateSerial(2026, 5, 20), "総務", "ペン", 6), _
Array(DateSerial(2026, 6, 1), "営業", "ファイル", 30))
For i = 0 To UBound(items)
ws.Range("A" & (i + 2) & ":D" & (i + 2)).Value = items(i)
Next i
ws.Range("A2:A9").NumberFormat = "yyyy/m/d"
End Sub
Findメソッドの引数一覧
書式は 範囲.Find(What, After, LookIn, LookAt, SearchOrder, SearchDirection, MatchCase, MatchByte, SearchFormat) です。Microsoft Learn の Range.Find のページに載っている引数を整理します。
| 引数 | 必須 | 指定する値 | 前回の指定が残るか |
|---|---|---|---|
| What | 必須 | 探すデータ(文字列など) | - |
| After | 省略可 | このセルの「次」から探し始める単一セル。省略すると範囲の左上のセルの次から | - |
| LookIn | 省略可 | xlFormulas(数式)・xlValues(値)・xlComments・xlCommentsThreaded |
残る |
| LookAt | 省略可 | xlWhole(完全一致)・xlPart(部分一致) |
残る |
| SearchOrder | 省略可 | xlByRows(行方向)・xlByColumns(列方向) |
残る |
| SearchDirection | 省略可 | xlNext(次へ)・xlPrevious(前へ) |
- |
| MatchCase | 省略可 | True で大文字と小文字を区別。既定は False | - |
| MatchByte | 省略可 | True で全角は全角だけに一致。False で全角と半角を同じものとして扱う | 残る |
| SearchFormat | 省略可 | 検索する書式 | - |
同じページの解説には、LookIn・LookAt・SearchOrder・MatchByte の設定は、このメソッドを使うたびに保存され、次に引数を省略して呼ぶと保存された値が使われると書かれています。これらの引数を指定すると「検索」ダイアログの設定も変わり、ダイアログ側で設定を変えると保存された値も変わります。そのため、公式ページでも「毎回これらの引数を明示的に指定する」ことが勧められています。
Findで1件探す
品名の列から「付箋」を探し、同じ行の部署と数量を読みます。
Sub F01_FindOne()
Dim ws As Worksheet, c As Range
Set ws = Worksheets("Sheet1")
Set c = ws.Range("C2:C9").Find(What:="付箋", _
After:=ws.Range("C9"), LookIn:=xlValues, LookAt:=xlWhole, _
SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, MatchByte:=False)
If c Is Nothing Then
Debug.Print "見つかりませんでした"
Else
Debug.Print "セル: " & c.Address(False, False) & " / 行: " & c.Row
Debug.Print "部署: " & ws.Cells(c.Row, 2).Value & " / 数量: " & ws.Cells(c.Row, 4).Value
End If
End Sub
出力:
セル: C5 / 行: 5
部署: 総務 / 数量: 8
ポイントは3つです。
- 戻り値は
Setで Range 型の変数に受ける。Find は Range オブジェクトを返します。 If c Is Nothingで分岐してから使う。見つからないと Nothing が返ります。- After に範囲の最後のセルを指定する。理由は「見つからない原因」の章で説明します。
Find は選択範囲やアクティブセルを変えません(公式ページの記載)。見つけたセルを選択したいときは、分岐の中で c.Select を呼びます。
部分一致と完全一致を切り替える
LookAt に xlPart を指定すると部分一致、xlWhole を指定すると完全一致です。
Sub F04_PartialMatch()
Dim ws As Worksheet, rng As Range, c As Range
Set ws = Worksheets("Sheet1")
Set rng = ws.Range("C2:C9")
Set c = rng.Find(What:="ファ", After:=rng.Cells(rng.Cells.Count), _
LookIn:=xlValues, LookAt:=xlPart, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=False, MatchByte:=False)
If Not c Is Nothing Then Debug.Print "部分一致: " & c.Address(False, False) & " " & c.Value
Set c = rng.Find(What:="ファ", After:=rng.Cells(rng.Cells.Count), _
LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=False, MatchByte:=False)
Debug.Print "完全一致: " & IIf(c Is Nothing, "見つかりませんでした", "見つかりました")
End Sub
出力:
部分一致: C9 ファイル
完全一致: 見つかりませんでした
FindNextで全件を拾う
Microsoft Learn の Range.Find と Range.FindNext のページには、検索が指定範囲の終わりに達すると範囲の先頭に折り返すこと、折り返しで検索を止めるには、最初に見つかったセルのアドレスを保存し、その後に見つかるセルのアドレスと比べることが書かれています。この説明どおりに書いたのが次のコードです。
Sub F02_FindAll()
Dim ws As Worksheet, rng As Range, c As Range, firstAddress As String
Set ws = Worksheets("Sheet1")
Set rng = ws.Range("C2:C9")
Set c = rng.Find(What:="ノート", After:=rng.Cells(rng.Cells.Count), _
LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=False, MatchByte:=False)
If c Is Nothing Then
Debug.Print "見つかりませんでした"
Exit Sub
End If
firstAddress = c.Address
Do
Debug.Print c.Address(False, False) & ": " & ws.Cells(c.Row, 2).Value & " " & ws.Cells(c.Row, 4).Value
Set c = rng.FindNext(c)
If c Is Nothing Then Exit Do
Loop While c.Address <> firstAddress
End Sub
サンプル表では、品名が「ノート」の C2・C4・C6 を順に処理し、次の FindNext が C2 に戻ったところでループを抜けます。
| 行 | 役割 |
|---|---|
firstAddress = c.Address |
最初に見つけたセルのアドレスを控える |
Set c = rng.FindNext(c) |
いま見つけたセルの次から、同じ条件で探す |
If c Is Nothing Then Exit Do |
ループの中でセルの値を書き換えた場合などに備えて、Nothing なら抜ける |
Loop While c.Address <> firstAddress |
最初のセルに戻ったら終了 |
Nothing の判定とアドレスの比較は、別々の行に分けて書きます。 Loop While Not c Is Nothing And c.Address <> firstAddress のように1行にまとめると、VBA の And は左右の両方を評価するため、c が Nothing のときに c.Address でエラーになります。互換モードで If c Is Nothing And c.Address = "x" Then を実行したところ、エラー番号 91 が発生しました。
行番号で終了を判定する書き方(c.Row を比べる)は、検索範囲が1列のときは同じ結果になりますが、複数列の範囲では同じ行に2件あると途中で止まります。Address なら列も含めて比べられます。
Findで複数条件(AND)に合う行を拾う
Find が受け取れる検索値は What の1つです。1つ目の条件を Find で絞り、残りの条件は見つけた行の別の列を If で調べます。 次のコードは「品名がノート、かつ部署が営業、かつ数量が10以上」の行を拾います。
Sub F03_FindTwoConditions()
Dim ws As Worksheet, rng As Range, c As Range, firstAddress As String, hit As Long
Set ws = Worksheets("Sheet1")
Set rng = ws.Range("C2:C9")
Set c = rng.Find(What:="ノート", After:=rng.Cells(rng.Cells.Count), _
LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=False, MatchByte:=False)
If Not c Is Nothing Then
firstAddress = c.Address
Do
If ws.Cells(c.Row, 2).Value = "営業" And ws.Cells(c.Row, 4).Value >= 10 Then
hit = hit + 1
Debug.Print c.Row & "行目: " & ws.Cells(c.Row, 2).Value & " " & ws.Cells(c.Row, 4).Value
End If
Set c = rng.FindNext(c)
If c Is Nothing Then Exit Do
Loop While c.Address <> firstAddress
End If
Debug.Print "該当: " & hit & "件"
End Sub
サンプル表で3つの条件に合うのは6行目(営業・ノート・12)の1件です。条件が増えて If が長くなってきたら、後半の AutoFilter か配列走査に切り替えると読みやすくなります。
Findで「見つからない」原因の一覧表
| 症状 | 原因 | 公式リファレンスの記載 | 対処 |
|---|---|---|---|
| 手作業で検索した後から、マクロで見つからなくなった | LookIn・LookAt・SearchOrder・MatchByte が前回の設定のまま | これらの設定は使うたびに保存され、省略すると保存値が使われる。「検索」ダイアログとも共有される | 4つの引数を毎回書く |
| 数式セルの計算結果が見つからない | LookIn が xlFormulas になっている |
LookIn は xlFormulas(数式)か xlValues(値)などを指定する |
表示されている値を探すなら LookIn:=xlValues |
| 一部だけ合っている文字列が見つからない | LookAt が xlWhole になっている |
LookAt は xlWhole か xlPart |
部分一致は LookAt:=xlPart |
| 全角と半角の違いで見つからない | MatchByte が True になっている | True で全角は全角だけに一致、False で半角とも一致 | MatchByte:=False を書く |
| 1件目が最後に見つかる(順番がずれる) | After を省略している | 検索は After のセルの次から始まり、そのセル自身は折り返すまで検索されない。省略時は左上のセルの次から | After に範囲の最後のセルを渡す |
| 実行時エラー 91 で止まる | Nothing のままプロパティを使っている | 見つからないと Nothing を返す | If c Is Nothing Then で分岐する |
| 日付が見つからない | 日付を文字列で探している | - | 日付型の値どうしで比べる(下のコード) |
検索設定は毎回すべて書く
対処の基本形です。この形をコピーして What と範囲だけ変えれば、前回の設定に左右されません。
Set c = rng.Find(What:="探す値", After:=rng.Cells(rng.Cells.Count), _
LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, _
SearchDirection:=xlNext, MatchCase:=False, MatchByte:=False)
数式セルで LookIn の違いを確かめました。F2 に =D2*2(計算結果は 20)を入れて互換モードで検索すると、次の結果でした。
| What | LookIn | 結果 |
|---|---|---|
| "20" | xlValues | 見つかる |
| "20" | xlFormulas | Nothing |
| "D2"(部分一致) | xlFormulas | 見つかる |
| "D2"(部分一致) | xlValues | Nothing |
Afterに範囲の最後のセルを渡す
After を省略すると、検索は範囲の左上のセルの「次」から始まります。左上のセル自身は、折り返して戻ってくるまで検索されません。先頭のセルから順に見つけたいときは、範囲の最後のセルを After に渡します。
Set c = rng.Find(What:="ノート", After:=rng.Cells(rng.Cells.Count), _
LookIn:=xlValues, LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext)
rng.Cells(rng.Cells.Count) は範囲の最後のセルです。「最後のセルの次」は折り返して先頭のセルになるので、先頭から順に探せます。
Nothing判定の漏れで実行時エラー91になる例
存在しない「消しゴム」を探し、分岐せずに c.Row を使った例です。
Sub F06_Error91()
Dim c As Range
On Error GoTo EH
Set c = Worksheets("Sheet1").Range("C2:C9").Find(What:="消しゴム", _
LookIn:=xlValues, LookAt:=xlWhole)
Debug.Print c.Row
Exit Sub
EH:
Debug.Print "実行時エラー " & Err.Number
End Sub
出力:
実行時エラー 91
Microsoft Learn のエラー 91(オブジェクト変数または With ブロック変数が設定されていません)のページでは、有効な参照が入っていないオブジェクト変数を使うとこのエラーになると説明されています。Find の直後に If c Is Nothing Then を置けば、この分岐で受け止められます。
日付は日付型の値どうしで比べる
日付セルは、文字列で探すと表示形式や指定のしかたの影響を受けます。日付型の値を作って、セルの Value と直接比べる書き方にすると、表示形式を変えても同じコードで動きます。件数が多いときは、同じ比較を Match に任せる書き方もあります。
Sub F07_DateSearch()
Dim ws As Worksheet, rng As Range, c As Range, pos As Variant, target As Date
Set ws = Worksheets("Sheet1")
Set rng = ws.Range("A2:A9")
target = DateSerial(2026, 4, 15)
pos = Application.Match(CLng(target), rng, 0)
If IsError(pos) Then
Debug.Print "Match: 見つかりませんでした"
Else
Debug.Print "Match: " & rng.Cells(pos).Address(False, False)
End If
For Each c In rng.Cells
If c.Value = target Then
Debug.Print "For Each: " & c.Address(False, False)
Exit For
End If
Next c
End Sub
Application.Match には、日付をシリアル値(CLng で整数にした値)で渡しています。Match の戻り値は範囲の中での位置なので、rng.Cells(pos) でセルに直します。
AutoFilterで条件に合う行を抽出してコピーする
AutoFilterの引数と演算子
書式は 範囲.AutoFilter(Field, Criteria1, Operator, Criteria2, SubField, VisibleDropDown) です。
| 引数 | 内容(Microsoft Learn の記載) |
|---|---|
| Field | 絞り込む列の番号。範囲の左端の列が 1 |
| Criteria1 | 条件(文字列)。"=" で空白のセル、"<>" で空白でないセル。省略するとすべて |
| Operator | XlAutoFilterOperator の定数 |
| Criteria2 | 2つ目の条件。Criteria1 と Operator と組み合わせて複合条件を作る。日付の列を年・月・日で絞る指定にも使う |
| VisibleDropDown | True(既定)で見出しの矢印を表示、False で隠す |
引数をすべて省略すると、指定した範囲のオートフィルターの矢印の表示・非表示が切り替わります(同ページの解説)。同じ解説には、Excel for Mac はこのメソッドに対応しておらず、Selection や ListObject の同様のメソッドが使えるという注記もあります。
| Operator の定数 | 意味 |
|---|---|
xlAnd |
Criteria1 と Criteria2 の AND |
xlOr |
Criteria1 と Criteria2 の OR |
xlFilterValues |
値の一覧で絞る(Criteria1 に配列を渡す) |
xlTop10Items / xlBottom10Items |
上位/下位の項目(個数を Criteria1 に指定) |
xlTop10Percent / xlBottom10Percent |
上位/下位のパーセント |
xlFilterCellColor / xlFilterFontColor / xlFilterIcon |
セルの色/フォントの色/アイコン |
xlFilterDynamic |
動的フィルター |
可視セルだけを別シートへコピーする定型コード
絞り込んだ後の処理は、条件が変わっても同じです。共通のプロシージャにしておきます。
Sub CopyVisibleTo(ByVal src As Range, ByVal destSheetName As String)
Dim dst As Worksheet, hitCount As Long
Set dst = Worksheets(destSheetName)
dst.Cells.Clear
hitCount = src.Columns(1).SpecialCells(xlCellTypeVisible).Count - 1
If hitCount = 0 Then
Debug.Print "該当 0件(コピーしません)"
Else
src.SpecialCells(xlCellTypeVisible).Copy Destination:=dst.Range("A1")
Debug.Print "該当 " & hitCount & "件をコピー"
End If
End Sub
| 行 | 役割 |
|---|---|
src.Columns(1).SpecialCells(xlCellTypeVisible).Count - 1 |
1列目で見えているセルの数から、見出しの1を引いて該当件数を出す |
If hitCount = 0 |
見出しだけが見えている=該当0件 |
src.SpecialCells(xlCellTypeVisible).Copy Destination:=… |
見えているセルだけを、見出しごと抽出先へコピー |
xlCellTypeVisible は「すべての可視セル」を表す XlCellType の定数、Copy の Destination はコピー先の範囲です(省略するとクリップボードへコピー)。見出しを含む範囲で数えるのがポイントで、見出しは絞り込んでも必ず見えているため、該当0件でも件数の計算がエラーにならず、0 という数で分岐できます。
条件1つで抽出する
Sub A01_FilterOne()
Dim ws As Worksheet, rng As Range
Set ws = Worksheets("Sheet1")
ws.AutoFilterMode = False
Set rng = ws.Range("A1").CurrentRegion
rng.AutoFilter Field:=2, Criteria1:="総務"
CopyVisibleTo rng, "Sheet2"
ws.AutoFilterMode = False
End Sub
最初の ws.AutoFilterMode = False は、前回の絞り込みが残っていた場合に解除するための行です。AutoFilterMode に False を設定すると、オートフィルターの矢印が取り除かれます(True は設定できません)。最後にも同じ行を置いて、元の表を全行表示に戻しています。矢印を残したまま全行を表示したいときは ws.ShowAllData を使います。ShowAllData は絞り込み中のシートで呼ぶメソッドなので、If ws.FilterMode Then ws.ShowAllData と分岐して呼びます。
同じ列でAND・ORを指定する
1つの列に2つの条件を付けるときは、Operator に xlAnd か xlOr を指定します。
Sub A02_FilterAndSameColumn()
Dim ws As Worksheet, rng As Range
Set ws = Worksheets("Sheet1")
ws.AutoFilterMode = False
Set rng = ws.Range("A1").CurrentRegion
rng.AutoFilter Field:=4, Criteria1:=">=5", Operator:=xlAnd, Criteria2:="<=10"
CopyVisibleTo rng, "Sheet2"
ws.AutoFilterMode = False
End Sub
Sub A04_FilterOr()
Dim ws As Worksheet, rng As Range
Set ws = Worksheets("Sheet1")
ws.AutoFilterMode = False
Set rng = ws.Range("A1").CurrentRegion
rng.AutoFilter Field:=3, Criteria1:="ペン", Operator:=xlOr, Criteria2:="付箋"
CopyVisibleTo rng, "Sheet2"
ws.AutoFilterMode = False
End Sub
別々の列でANDを指定する
列ごとに AutoFilter を呼ぶと、条件が重なって AND になります。Microsoft Learn の使用例でも、AutoFilter を2回続けて呼び、「1つ目の条件、かつ2つ目の条件」の行を表示しています。
Sub A03_FilterAndTwoColumns()
Dim ws As Worksheet, rng As Range
Set ws = Worksheets("Sheet1")
ws.AutoFilterMode = False
Set rng = ws.Range("A1").CurrentRegion
rng.AutoFilter Field:=2, Criteria1:="営業"
rng.AutoFilter Field:=3, Criteria1:="ノート"
CopyVisibleTo rng, "Sheet2"
ws.AutoFilterMode = False
End Sub
3つ以上の値のどれかで抽出する(配列とxlFilterValues)
xlOr で指定できる条件は Criteria1 と Criteria2 の2つです。3つ以上の値は、Criteria1 に配列を渡し、Operator に xlFilterValues を指定します。
Sub A05_FilterValues()
Dim ws As Worksheet, rng As Range
Set ws = Worksheets("Sheet1")
ws.AutoFilterMode = False
Set rng = ws.Range("A1").CurrentRegion
rng.AutoFilter Field:=3, Criteria1:=Array("ペン", "付箋", "電池"), Operator:=xlFilterValues
CopyVisibleTo rng, "Sheet2"
ws.AutoFilterMode = False
End Sub
日付の範囲で抽出する
開始日以上・終了日以下を xlAnd でつなぎます。日付はシリアル値(CLng で整数にした値)にして条件の文字列に入れています。
Sub A06_FilterDateRange()
Dim ws As Worksheet, rng As Range, fromDate As Date, toDate As Date
Set ws = Worksheets("Sheet1")
ws.AutoFilterMode = False
Set rng = ws.Range("A1").CurrentRegion
fromDate = DateSerial(2026, 4, 10)
toDate = DateSerial(2026, 5, 9)
rng.AutoFilter Field:=1, Criteria1:=">=" & CLng(fromDate), _
Operator:=xlAnd, Criteria2:="<=" & CLng(toDate)
CopyVisibleTo rng, "Sheet2"
ws.AutoFilterMode = False
End Sub
月単位・年単位で絞るときは、Criteria2 に Array(レベル, 日付) を渡す方法が Microsoft Learn に載っています。レベルは 0 が年、1 が月、2 が日で、日付にはその期間に含まれる有効な日付を1つ指定します。同ページには、2019年1月と2月の行をすべて表示する次の使用例があります。
Worksheets("Sheet1").ListObjects("Table1").Range.AutoFilter _
Field:=1, _
Criteria2:=Array(1, "1/31/2019", 1, "2/28/2019")
該当0件のときの分岐
存在しない品名で絞り込むと、見出しだけが見えている状態になります。定型コードの hitCount が 0 になり、コピーを行わずにメッセージだけを出します。
Sub A07_FilterNoHit()
Dim ws As Worksheet, rng As Range
Set ws = Worksheets("Sheet1")
ws.AutoFilterMode = False
Set rng = ws.Range("A1").CurrentRegion
rng.AutoFilter Field:=3, Criteria1:="消しゴム"
CopyVisibleTo rng, "Sheet2"
ws.AutoFilterMode = False
End Sub
条件と、サンプル表で条件に合う行
サンプル表の8行のうち、各コードの条件に合う行番号です。
| コード | 条件 | 条件に合う行 | 件数 |
|---|---|---|---|
| A01_FilterOne | 部署が総務 | 2・5・8 | 3 |
| A02_FilterAndSameColumn | 数量が5以上かつ10以下 | 2・4・5・8 | 4 |
| A04_FilterOr | 品名がペンまたは付箋 | 3・5・8 | 3 |
| A03_FilterAndTwoColumns | 部署が営業かつ品名がノート | 6 | 1 |
| A05_FilterValues | 品名がペン・付箋・電池のどれか | 3・5・7・8 | 4 |
| A06_FilterDateRange | 日付が 2026/4/10 から 2026/5/9 | 4・5・6・7 | 4 |
| A07_FilterNoHit | 品名が消しゴム | なし | 0 |
Find・AutoFilter・Match関数・配列走査の選び方
| 方法 | 得意なこと | 複数条件 | 見つからないとき | 向く場面 |
|---|---|---|---|---|
| Find/FindNext | シートや複数列の範囲から値のあるセルを探す | 1条件+If で追加 | Nothing | どの列にあるか分からない値を探す |
| AutoFilter | 条件に合う行をまとめて見せる・写す | AND・OR・値の一覧・日付の期間 | 見出しだけが見える | 抽出結果を別シートに作る |
| Application.Match | 1行または1列の中での位置を返す | 1条件 | エラー値(IsError で判定) | キーの列から行番号を引く |
| 配列走査 | 読み込んだ値を For で1件ずつ調べる | If で自由に書ける | 件数が 0 | 条件が複雑、判定しながら集計する |
Match は、WorksheetFunction.Match のページで、照合の種類が 0 のとき最初に完全一致した値の位置を返し、大文字と小文字を区別せず、見つからないと #N/A エラーになると説明されています。同ページの使用例と同じく、Application.Match の結果を Variant 型で受けて IsError で判定します。
Sub F08_Match()
Dim ws As Worksheet, pos As Variant
Set ws = Worksheets("Sheet1")
pos = Application.Match("電池", ws.Range("C2:C9"), 0)
If IsError(pos) Then
Debug.Print "見つかりませんでした"
Else
Debug.Print "範囲内の位置: " & pos & " / シートの行: " & (pos + 1)
End If
pos = Application.Match("消しゴム", ws.Range("C2:C9"), 0)
Debug.Print "消しゴム: " & IIf(IsError(pos), "見つかりませんでした", "見つかりました")
End Sub
配列走査は、範囲の Value を Variant 型の変数に読み込み、行ごとに If で条件を調べます。次のコードは「部署が総務、かつ数量が8以上」の行を拾います。
Sub F09_ArrayScan()
Dim ws As Worksheet, data As Variant, r As Long, hit As Long
Set ws = Worksheets("Sheet1")
data = ws.Range("A2:D9").Value
For r = LBound(data, 1) To UBound(data, 1)
If data(r, 2) = "総務" And data(r, 4) >= 8 Then
hit = hit + 1
Debug.Print (r + 1) & "行目: " & data(r, 3) & " " & data(r, 4)
End If
Next r
Debug.Print "該当: " & hit & "件"
End Sub
出力:
2行目: ノート 10
5行目: 付箋 8
該当: 2件
読み込んだ配列の添字は 1 から始まるので、シートの行番号に直すときは、範囲の開始行ぶん(ここでは 1)を足します。
条件から選ぶ
| 条件 | 選ぶ方法 |
|---|---|
| 1件あれば十分で、位置(セル)が欲しい | Find |
| 同じ値のセルを全部処理したい | Find + FindNext |
| キーが1列にまとまっていて、行番号が欲しい | Application.Match |
| 条件に合う行を別シートへ写したい | AutoFilter + 可視セルのコピー |
| 「A かつ(B または C)」のように条件が入り組んでいる | 配列走査 |
| 日付や数値を型のまま比べたい | 配列走査、または Match |
確かめて分かったこと
- 保存される検索設定は LookIn・LookAt・SearchOrder・MatchByte の4つと公式ページに明記されています。「検索」ダイアログと共有されるため、手作業の検索がマクロの結果に影響します。
- 公式ページの FindNext の使用例は、見つけたセルの値を書き換えるコードです。書き換えると検索値に合うセルが無くなり、最後は Nothing が返ってループが終わります。値を書き換えない処理では Nothing にならないので、Address の比較が必要です。
- Nothing の判定とアドレスの比較を And で1行にまとめると、エラー番号 91 になりました。Nothing の判定は
If c Is Nothing Then Exit Doと別の行に分けます。 - 数式セルは LookIn の指定で結果が逆になりました。計算結果の 20 は xlValues で見つかり、数式の中の D2 は xlFormulas で見つかります。
- 該当0件の絞り込みで、定型コードの件数は 0 になりました。見出しを含めて数えているので、可視セルが1つも無い状態にはなりません。
- LibreOffice の VBA 互換モードでは、FindNext が用意されておらず、列を変えて AutoFilter を2回呼ぶと後の条件だけが残りました。Excel 用に書いたマクロを Calc で動かす場合は、この2点を配列走査などに置き換える必要があります。
よくある質問
Q. Find で値があるのに見つからないときは? A. LookIn・LookAt・MatchByte を引数で明示しているかを最初に確かめます。この3つと SearchOrder は前回の設定が残るため、省略すると、直前の検索(手作業の検索も含む)の設定で探すことになります。
Q. Find と FindNext の違いは? A. Find は条件を指定して最初の1件を探し、FindNext は直前の Find と同じ条件で次の1件を探します。全件を拾うときは、Find の後に FindNext をループで呼びます。
Q. FindNext のループが終わらないときは? A. 終了条件を、最初に見つけたセルの Address との比較にします。検索は範囲の終わりから先頭へ折り返すため、Nothing になるのを待つ条件だけでは、値を書き換えない処理では終わりません。
Q. AutoFilter で3つ以上の条件を指定するには?
A. Criteria1 に Array("ペン", "付箋", "電池") のような配列を渡し、Operator に xlFilterValues を指定します。別々の列の条件を重ねる場合は、列ごとに AutoFilter を呼びます。
Q. AutoFilter で抽出結果が0件かどうかを調べるには?
A. 見出しを含む1列で、可視セルの数を数えます。範囲.Columns(1).SpecialCells(xlCellTypeVisible).Count が 1 なら、見えているのは見出しだけなので0件です。
まとめ
- 1件なら Find、全件なら FindNext、行をまとめて写すなら AutoFilter。
- Find の戻り値は必ず
Is Nothingで分岐してから使います。分岐が無いと実行時エラー 91 になります。 - LookIn・LookAt・SearchOrder・MatchByte は毎回書く。前回の設定が残る引数です。
- FindNext は最初の Address に戻ったら終了。Nothing の判定とは別の行に書きます。
- After に範囲の最後のセルを渡すと、先頭のセルから順に見つかります。
- AutoFilter の複数条件は、同じ列なら xlAnd・xlOr、3つ以上は配列と xlFilterValues、別の列は列ごとに呼ぶ。
- 0件の判定は、見出しを含めた可視セルの数で行い、コピーの前に分岐します。
参考・出典
- Microsoft Learn「Range.Find method (Excel)」「Range.FindNext method (Excel)」「XlFindLookIn enumeration (Excel)」(2026-10-05 確認)
- Microsoft Learn「Range.AutoFilter method (Excel)」「XlAutoFilterOperator enumeration (Excel)」「Worksheet.AutoFilterMode property (Excel)」「Worksheet.FilterMode property (Excel)」「Worksheet.ShowAllData method (Excel)」(2026-10-05 確認)
- Microsoft Learn「Range.SpecialCells method (Excel)」「XlCellType enumeration (Excel)」「Range.Copy method (Excel)」「WorksheetFunction.Match method (Excel)」(2026-10-05 確認)
- Microsoft Learn「Object variable not set (Error 91)」(2026-10-05 確認)
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「VBA Findの使い方とAutoFilter抽出|複数条件のコード集」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。