TL;DR —
Range.AdvancedFilterは、ビューではなく データ を手渡す唯一のフィルターです。 1 回の呼び出しで、一意なリスト や 条件に一致した行の集合 を、ループなしで、何も削除 せずに別の場所へコピーできます。これを解き放つ考えが 2 つあります。第一に、ActionがxlFilterInPlace(AutoFilter のように行を隠す)とxlFilterCopy(結果をCopyToRangeに コピーする — 強力なモード)を選び分けます。第二に、その「WHERE 句」はコードではありません — 条件範囲、つまり見出しが 元の見出しと正確に一致しなければならない 小さなセルのブロック です。Unique:=Trueを添えれば、元をそのままに、一意なリストが 1 行で手に入ります。
' B 列から Region の値の重複なしリストを E 列へ抽出する。非破壊的。
Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets("Sales")
ws.Range("B1:B1000").AdvancedFilter _
Action:=xlFilterCopy, _
CopyToRange:=ws.Range("E1"), _ ' E1 は B1 と同じ見出しを持つこと
Unique:=True ' 各値を 1 つずつ、元は変更なし
AdvancedFilter は、人が最後に手を伸ばすのに、本当は最初に手を伸ばすべき道具です。結果を
データとして 必要とするとき — 重複のないリスト、条件に一致する行のエクスポート、元をそのまま
残す重複除去済みのコピー — 本能は If と Dictionary を伴う For Each ループを書かせます。
Excel にはまさにこのためのクエリエンジンがすでにあります。本記事は、それを定義づける 2 つの
考え — 隠す代わりにコピーできる、そして条件はセルの中に置かれる — を軸に組み立てられて
います。
この記事で学べること
- 考え方の軸 — 範囲のための簡易 SQL。ただ見るのではなく抽出する
- その場か、コピーか —
xlFilterInPlaceとxlFilterCopy - 条件範囲 — WHERE 句はコードではなくセルの中に置かれる
Unique:=True— 何も削除せずに重複のないリストを作る- 空の出力を返す、見出し不一致の罠
AdvancedFilterとAutoFilterとRemoveDuplicates
考え方の軸:範囲のための簡易 SQL
AdvancedFilter を、範囲に取り付けられた小さなクエリエンジンだと考えてください。AutoFilter は
「どの行を 見たい か?」に答え、残りをその場で隠します。AdvancedFilter はもっと大きな問いに
答えます — 「一致する行をくれ、どこかに置いて使える 新しいデータの集合 として」。その場で
フィルターすることもできますが、その存在理由はコピーモードです — 元の範囲、任意の条件の組、
そして一致した(あるいは一意な)行を、選んだ宛先へ書き出します。
この捉え直しが大事なのは、ループのまるごと 1 カテゴリを置き換えるからです。「一意な顧客を取得 する」「1000 を超えるすべての注文をレポートシートに引き出す」「重複のない商品コードを列挙する」 — これらは反復ではなく、1 回の呼び出しでの抽出です。このイメージ — AdvancedFilter はデータを生み、 AutoFilter はビューを生む — を頭に置いておけば、どちらがそのタスクに必要かが分かります。
その場か、コピーか:xlFilterInPlace と xlFilterCopy
Action 引数が分かれ道です。
xlFilterInPlaceは、AutoFilterとまったく同じように、一致しない行を元の範囲の中でその場で 隠します。データは動きません。フィルターされたビューが得られます。あとでそれをクリアするにはws.ShowAllDataを呼びます。xlFilterCopyは元をそのままにして、一致する行をCopyToRangeに コピーします。これがAdvancedFilterを特別にするモードです — 非破壊的で、独立した使えるデータのブロックを生みます。
' コピーモード - たいていはこれが欲しい。
ws.Range("A1").CurrentRegion.AdvancedFilter _
Action:=xlFilterCopy, _
CriteriaRange:=ws.Range("H1:H2"), _ ' WHERE 句(後述)
CopyToRange:=ws.Range("K1"), _ ' 結果が着地する場所
Unique:=False
xlFilterCopy を渡すなら CopyToRange を 必ず 与えます。xlFilterInPlace を渡すなら
与えてはいけません(取り違えるとどちらの場合も Excel はエラーになります)。迷ったらコピー
です — 元には決して触れません。
条件範囲:WHERE 句はセルの中に置かれる
ほかの言語から来ると異質に感じる部分がこれです。AdvancedFilter は条件を文字列や式として
取りません。その条件は 条件範囲 の中に置かれます — ワークシートのセルの小さなブロックです。
先頭行は 元と一致する列見出し を保持し、その下の行が条件を保持します。
H I
1 Region Amount
2 West >1000
この条件範囲は「Region が West かつ Amount > 1000」を意味します。同じ行 の条件は AND、
別々の行 に積んだ条件は OR です。だから次の 2 行は —
H
1 Region
2 West
3 East
— 「Region が West または East」を意味します。このブロックは、マクロが所有するセル(作業用の
一角、あるいは隠しシート)に作り、そこへ CriteriaRange を向ければよいのです。
ws.Range("A1").CurrentRegion.AdvancedFilter _
Action:=xlFilterCopy, _
CriteriaRange:=ws.Range("H1:I2"), _
CopyToRange:=ws.Range("K1")
CriteriaRange をまるごと省けば、条件は何も適用されません — これを Unique:=True と組み合わせる
のが、まさに素の重複なしリストを得る方法です。
Unique:=True — 何も削除せずに重複のないリストを作る
Unique:=True を設定すると、AdvancedFilter は重複のない行(単一列なら値)を 1 つずつ 返し
ます — 重複の削除 と同じ結果ですが、一意な値を外へ コピーし、元をそのまま残す 点が
違います。このたった 1 つの性質こそ、AdvancedFilter が安全な重複除去の方法である理由です。
' 重複のない顧客名を K 列へ、元のリストはそのまま。
ws.Range("C1:C5000").AdvancedFilter _
Action:=xlFilterCopy, _
CopyToRange:=ws.Range("K1"), _
Unique:=True
RemoveDuplicates が取り消しなしにその場で削除するのに対し、こちらは真新しい重複除去済みの
リストを手渡し、元を危険にさらすことは決してありません。「データを壊さずに VBA で一意な値を
得るには?」と聞かれたら、これが答えです。
空の出力を返す、見出し不一致の罠
AdvancedFilter が「何も返さない」第 1 位の理由は、見出しの不一致です。CriteriaRange の
見出しと CopyToRange の見出しは、どちらも元の見出しと 正確に 一致しなければなりません —
同じつづり、同じ空白、大文字小文字を無視して同じテキスト。「Reigon」(打ち間違い)という条件
見出しや、先頭セルが空白または誤ってラベル付けされた CopyToRange は、エラーを出さずに 空
または間違った出力を生みます。
これを防ぐ習慣が 2 つあります。
- 条件とコピー先の見出しは、打ち直すのではなく 本物の見出しセルをコピーして 作ること。
- 別のシートにフィルターするなら、古いルールを思い出してください。古典的な
AdvancedFilterはCopyToRangeが アクティブシート上 にあることを求めます。頑健なパターンは、結果が着地する シートからフィルターを実行するか、元のシート上の作業範囲にフィルターしてから結果をあとで移す ことです。
出力が空で返ってきたら、ほかの何よりも先に見出しを確認しましょう。
AdvancedFilter と AutoFilter と RemoveDuplicates
混同するほど重なり、区別が効くほど違う 3 つです。
AutoFilter— ビュー。行をその場で隠してユーザーに部分集合を 見せます。何もコピーも削除もされません。フィルターした範囲を 見せる ために手を伸ばします。AdvancedFilter(コピーモード) — クエリ。一致した、あるいは一意な行を、非破壊的に 新しい場所へ抽出します。結果を データとして 必要とするときに手を伸ばします。RemoveDuplicates— 削除。データをその場で縮め、各値の 最初を残し、取り消しなし。元そのものを本当に小さくしたく、バックアップがあるときにだけ手を 伸ばします。
覚えておく価値のある一言はこうです。AutoFilter は見せ、RemoveDuplicates は壊し、
AdvancedFilter は元に触れずに 抽出する — 重複のないリストや条件に一致したコピーを。
フィルターしたリストや一意なリストを作るためにループを書いている自分に気づいたら、それは
AdvancedFilter です。
ExcelMaster の活用
AdvancedFilter が強力なのは、まさに扱いが細かいからです — その場かコピーかの分岐、一字一句
一致する見出しとともにセルの中に置かねばならない条件範囲、コピー先の宛先とそのアクティブ
シートのルール、Unique フラグ。見出しをどれか 1 つでも間違えれば、静かに、何も返しません。
ExcelMaster なら、
クエリを説明するだけで済みます。「West 地域の 1000 超の注文をすべて新しいシートに引き出して」
「商品コードの重複のないリストをちょうだい」と言えば、元からコピーした見出しとともに条件範囲を
並べ、有効な CopyToRange でコピーモードを選び、重複のない値が欲しいときは Unique を設定し、
元データはそのまま残します。ブックもコードもあなたの手元に残り、打ち間違えた条件見出しがなぜ
空の結果を返したのかと悩む 30 分だけを飛ばせます。
よくある質問
VBA で Advanced Filter を使うには?
元の範囲に対して AdvancedFilter を呼びます。結果をどこか別の場所にコピーするには
(CopyToRange とともに)Action:=xlFilterCopy を、一致しない行を隠すには xlFilterInPlace を
選びます。条件には CriteriaRange を与えるか、重複のないリストを抽出するには条件なしで
Unique:=True を設定します。コピーモードでは元データは変更されません。
VBA の Advanced Filter で一意な値を抽出するには?
コピーモードで、条件なしに Unique:=True を使います。rng.AdvancedFilter Action:=xlFilterCopy, CopyToRange:=ws.Range("E1"), Unique:=True のように。重複のない各値を 1 つずつ宛先に書き出し、
元をそのまま残します — その場で削除する RemoveDuplicates とは違います。CopyToRange の見出しは
元の見出しと一致しなければなりません。
VBA の Advanced Filter が何も返さないのはなぜ?
ほぼ必ず見出しの不一致です。CriteriaRange と CopyToRange の先頭行の見出しは、元の見出しと
正確に一致しなければなりません(打ち間違いや空白の見出しは、エラーなしに空の出力を返します)。
見出しは打ち直さずに本物のセルをコピーし、コピーモードのフィルターには有効な CopyToRange が
あることを確かめましょう。
VBA の AutoFilter と Advanced Filter の違いは?
AutoFilter は ビュー を生みます — 一致しない行をその場で隠し、何もコピーしません。
AdvancedFilter は データ を生みます — コピーモードでは、元を変えずに一致した、あるいは一意な
行を新しい場所へ抽出し、AutoFilter にはできない複雑な AND/OR 条件と一意抽出に対応します。
VBA の Advanced Filter で条件はどう働く?
条件はコードではなく、セルの範囲の中に置かれます。先頭行は元と一致する見出しを保持し、同じ行の
条件は AND で、別々の行の条件は OR で結合されます。そのブロックへ CriteriaRange を向けます。
条件を何も適用しないなら省きます(Unique:=True と組み合わせると便利です)。
検証環境
動作確認: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-08-10。
関連ガイド: VBA AutoFilter · VBA Remove Duplicates · VBA Sort · VBA Find · VBA Range
